perm filename COMSCH.MSG[SCH,LSP]7 blob
sn#801288 filedate 1985-08-12 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00001 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 ENDMK
C⊗;
∂29-Nov-84 1009 RPG Comments on the Preliminary Report (2 pages)
∂28-Nov-84 0331 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Comments on the Preliminary Report (2 pages)
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 28 Nov 84 03:31:05 PST
Received: from unc by csnet-relay.csnet id a021839; 28 Nov 84 6:30 EST
Received: by unc (4.12/4.7) id AA17493; Tue, 27 Nov 84 23:00:58 est
Date: Tue, 27 Nov 84 23:00:58 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8411280400.AA17493@unc>
To: scheme@mit-mc.ARPA
Subject: Comments on the Preliminary Report (2 pages)
Cc: willc%indiana.csnet@csnet-relay.arpa
Comments on Essential Scheme
These comments are arranged in four categories: lambda syntax, other
special forms, functions, and lexical matters. I feel quite strongly
about the issues I outline here. I have other minor gripes (don't we
all) that I didn't bother to include here, for fear they would water
down the substantive issues.
Lambda Syntax
For several years my Scheme system has had a syntax for lambda
expressions that allows naming of the closure within the body of the
closure for enhanced readability and efficiency. The syntax is:
(lambda name formals . body)
where name is a symbol bound lexically to the closure within body,
formals is a list of formal parameters, and body is a set of zero or
more forms to execute. Name may be omitted and there is no ambiguity
since formals is always a list.
This feature, which I have called "named lambda," allows terse,
referentially transparent recursive function definitions. It is similar
to the optional "rec," special form, but is shorter and perhaps more
easily optimized than rec. It is quite a bit shorter than using
"letrec." For example, the boring factorial function looks like:
(lambda fact (x) (if (= x 0) 1 (* x (fact (- x 1))))),
a totally self contained definition.
Named lambda generalizes to named let, something which seems to have
appeared elsewhere independently. It looks like:
(let name ((x1 v1) (x2 v2) ...) . body),
where name may again be omitted. It translates into:
((lambda name (x1 x2 ...) . body) v1 v2 ...),
and replaces the old iterate expression.
Unfortunately, the partial destructuring provided by the adopted lambda
syntax conflicts with the named lambda syntax, introducing an ambiguity
in some cases, as in:
(lambda f (g x) ...).
Is this a named lambda with two formals or an unnamed lambda with a
single &rest formal?
The partial destructuring syntax is merely a different syntax for the
&rest formal parameter adopted by Common Lisp. The only benefit to be
gained by not using the Common Lisp syntax is that some implementations
might generalize to full destructuring. I think it more likely that we
would want to generalize to optional arguments. Why not just use part
of the syntax adopted by Common Lisp? For now, we could make the &rest
syntax required and the &optional syntax optional.
If everyone dislikes the &rest syntax then I think we ought to resolve
the ambiguity with named lambda by requiring the name to be present.
This would improve code readability and facilitate optimization
regardless of the system the code is executed on.
Other Special Forms
1. The "if" special form should require an else part. This allows the
compiler/interpreter to make a sanity check for the user which might
save some grief, and seems a little cleaner. The macros "when" and
"unless" are the appropriate way to express the intended meaning.
2. Block is a much better name for the statement grouping special form
than "begin". Do we really need an artifact of Algol syntax in our
language? After all, it is a block of code, not a begin of code.
(If someone is worried about clashing with a process blocking function
they should name their function "block-process.")
3. Case expressions should allow single keys without putting them in a
list. The user rarely wants the single key to be a list (eq semantics
and all), so there really isn't any ambiguity. Since single keys are
probably the most common, case expressions will be less bulky.
For example,
(case x ((a) ...) ((b) ...) ((c d) ...) (else ...))
would simply be
(case x (a ...) (b ...) ((c d) ...) (else ...)).
Functions
1. Call/cc should be an alternative to call-with-current-continuation.
How are we ever going to get people to feel comfortable with something
so imposing that it requires 30 keystrokes to type in and takes up half
a line?
2. Transcendental functions should be required only in implementations
with floating point numbers, not just any implementation with numbers
other than integers. In particular, an implementation with rational or
interval arithmetic should not be bound to supporting transcendental
functions. (This was probably just a misstatement in Will's note.)
3. The length function should be generic, returning a value for all
reasonable arguments. There can still be individual functions list-
length, string-length, vector-length, and so on.
Lexical Matters
Scheme systems should be case sensitive. Let's not forget that symbols
have other uses than as Scheme identifiers. How can we implement
prolog-like variables in Scheme without being able to differentiate
between upper and lower case letters within the symbols? Does anyone
really still use an upper-case only terminal? Assuming case
sensitivity, all standard Scheme functions and special forms should be
written with entirely lower-case letters.
∂30-Nov-84 1658 RPG Re: Kent Dybvig's Comments on Scheme
∂30-Nov-84 1545 @MIT-MC:bartley%ti-csl.csnet@csnet-relay.arpa Re: Kent Dybvig's Comments on Scheme
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 30 Nov 84 15:44:40 PST
Received: from ti-csl by csnet-relay.csnet id a008334; 30 Nov 84 18:12 EST
Date: 30 Nov 1984 1147-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: Re: Kent Dybvig's Comments on Scheme
To: Scheme@mit-mc.ARPA
cc: Bartley%ti-csl.csnet@csnet-relay.arpa
Re: Kent Dybvig's comments on the preliminary report on Scheme
I'd like to briefly add my "votes" on Kent's suggestions and bring up
some additional complexities in the issues he raised.
Lambda Syntax
I prefer (REC name (LAMBDA args . body)) first, then MIT-style
NAMED-LAMBDA second. (I support both.) Will's discussion summarizes
my reasons quite well. We should NOT require all lambdas to be named.
IF without else part
I would not mind requiring WHEN in this case, making (IF a b)
syntactically incorrect. This allows better compile-time checking. I
use WHEN myself to make this distinction and find it useful. BTW, I do
NOT find UNLESS useful, since (WHEN (NOT ..)..) usually reads better.
BLOCK vs BEGIN vs LET()
As Will points out, the real question is whether the construct we have
in mind is a compound expression or an Algol-like block containing both
declarations and expressions to be evaluated. I prefer BEGIN for the
former and LET for the latter.
The problem is that Will suggests (paraphrasing someone else) that
(BEGIN ...) might be equivalent to (LET () ...). I have conflicting
thoughts on this. Pro: if they are the same, then I would vote to
remove BEGIN from the (essential) language as hopelessly redundant with
LET. Con: early papers by Steele and Sussman treat (BEGIN a b) as a
macro for ((LAMBDA (ignored-id) b) a), which is equivalent to
(LET ((ignored-id a)) b). Thus, BEGIN already is a scope-extending
operation.
This has the following practical consequence. What is the scope of FOO
in the following?
(define (f ...)
(define g ...)
(begin
(define foo ...))
body)
I understand that MIT Scheme "promotes" both G and FOO directly under
F. This hack is needed for macros that expand into multiple DEFINEs
and thus must be "wrapped" in something to be spliced in correctly.
If we define BEGIN in terms of LET, then the scope of FOO will have to
be confined to the scope of the BEGIN.
What should we do? I vote that BEGIN indicate a compound expression,
contrary to early Steele&Sussman, and that LET() be used for
Algol-style blocks.
CASE expressions with single keys
We will accept single keys in CASE expressions. If ELSE is to be a
single key in the last clause, however, it will have to be enclosed in
parentheses to avoid being interpreted as "otherwise".
CALL/CC
"CALL-WITH-CURRENT-CONTINUATION" is nonsense to the unititiated, too.
I will support both, but feel like it's silly to have the long name.
Must this be a procedure (e.g. a potential funarg) or can we treat it
as a special form?
Transcendental functions
What's the problem? Just call them "optional" as a group. What we've
been arguing is whether I have "true Scheme" if I have some kind of
representation for "real numbers" but don't support a certain set of
functions. This is irrational!! (sorry)
Generic LENGTH
I strongly abhor Common LISP-style genericity. As Will says, "generic"
operations on numbers with multiple REPRESENTATIONS is one thing, but
trying to be generic across different kinds of things is something
else.
Case-sensitive symbols
I feel very strongly that symbols, as processed by the reader, should
NOT be case sensitive and that (EQ? 'a 'A) be true. STRING->SYMBOL
should preserve case, however, and (EQ? '|a| '|A|) should be false.
-- David Bartley (Bartley @ TI-CSL)
-------
∂01-Dec-84 1049 RPG Kent Dybvig's Comments on Scheme
∂30-Nov-84 2036 @MIT-MC:JINX@MIT-OZ Kent Dybvig's Comments on Scheme
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 30 Nov 84 20:35:53 PST
Date: 30 Nov 1984 23:35 EST (Fri)
Message-ID: <JINX.12067849164.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: David Bartley <Bartley%ti-csl.csnet@CSNET-RELAY.ARPA>
Cc: Scheme@MIT-MC.ARPA
Subject: Kent Dybvig's Comments on Scheme
In-reply-to: Msg of 30 Nov 1984 12:47-EST from David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
BEGIN should certainly not add another contour. BEGIN is
equivalent to LET() if environments are not first class, but they are
in MIT Scheme. An incremental definition to the environment where the
subexpressions of the BEGIN expression are evaluated would have
different effects depending on whether a new contour was created or
not. I agree that BEGIN (for lack of a better name) should indicate a
compound expression and LET should be used for blocks.
Note that this is not contrary to all early Scheme papers
since in the Revised Report,
(BLOCK X Y) = ((LAMBDA (A B) (B)) X (LAMBDA () Y)).
X is evaluated in the environment where the BEGIN
expression appears, and Y is evaluated in an environment where no
bindings have been added. In a dialect without first-class
environments and without internal definitions, the environment where Y
is evaluated is the same as that where X is evaluated, thus no
contours have been added.
I think that there are only two valid reasons for adding
special forms:
- They provide a convenient syntax for something which
could be expressed only considerably more clumsily without them.
Example: COND (as compared to nested IFs). These are usually macros
which expand into the clumsier form.
- They provide an extension to the language which requires
special handling by the interpreter or compiler. Their effect could
otherwise not be achieved. Example: QUOTE. These are the "TRUE"
special forms.
I don't think that CALL-WITH-CURRENT-CONTINUATION falls in
either class, so there is no need to make it a special form. Besides,
a portable program would not be able to rename it since we have not
specified a way for adding syntactic extensions.
Allowing IF not to have an alternative sub-expression is
convenient because it is clear and eliminates the need for WHEN,
another special form. I don't like the proliferation of special forms
and would object strongly to requiring another one for this purpose.
I can't see that there is a difference between WHEN and IF in terms of
compile-time checking. IF with two subexpressions and IF with three
subexpressions can be treated as different beasts.
I agree with the remaining three points.
- Bill Rozas (JINX@MIT-MC)
∂05-Dec-84 1353 RPG Re: Kent Dybvig's Comments on Scheme
∂04-Dec-84 2015 @MIT-MC:HUDAK@YALE.ARPA Re: Kent Dybvig's Comments on Scheme
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 4 Dec 84 20:15:10 PST
Received: by YALE-BULLDOG.YALE.ARPA; 4 Dec 84 11:49:28 EST (Tue)
Message-Id: <8412041649.AA04845@YALE-BULLDOG.YALE.ARPA>
Received: from YALE-RING by YALE-RES via CHAOS; Tue, 4 Dec 84 11:37:43 EST
Subject: Re: Kent Dybvig's Comments on Scheme
Date: Tue, 4 Dec 84 11:37:46 EST
From: Paul Hudak <Hudak@YALE.ARPA>
To: Bill Rozas <JINX%MIT-OZ@MIT-MC>
Cc: Scheme@MIT-MC, Hudak@YALE.ARPA
In-Reply-To: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>, 30 Nov 1984 23:35 EST (Fri)
Not having participated in the workshop, I've been hesistant about
making comments on the various issues flying by recently, but I couldn't
resist responding to Bill Roza's comments on special forms:
I think that there are only two valid reasons for adding
special forms:
- They provide a convenient syntax for something which
could be expressed only considerably more clumsily without them.
Example: COND (as compared to nested IFs). These are usually macros
which expand into the clumsier form.
- They provide an extension to the language which requires
special handling by the interpreter or compiler. Their effect could
otherwise not be achieved. Example: QUOTE. These are the "TRUE"
special forms.
I think there's one other reason, which in a sense subsumes the first:
*readability*. In particular, with regard to IF having or not having
an alternative sub-expression, I find that when I'm reading code and
come across an IF expression, I look very hard to see if it has an
alternative branch. If it doesn't, I look again to be sure I didn't
miss it. I think this "convenient feature" degrades readability.
I agree with Bill Rozas that one shouldn't proliferate special forms,
but my reason is that they are typically complex, and their syntax
becomes hard to remember. However you can't get much simpler than
WHEN and UNLESS. Their use, in my opinion, greatly enhances
readability.
- Paul Hudak (hudak@yale)
∂07-Dec-84 1341 RPG [willc: preliminary report of workshop]
∂06-Dec-84 1909 KMP@MIT-MC [willc: preliminary report of workshop]
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 6 Dec 84 19:09:23 PST
Date: 6 December 1984 22:02-EST
From: Kent M Pitman <KMP @ MIT-MC>
Subject: [willc: preliminary report of workshop]
To: willc%indiana.csnet @ CSNET-RELAY
cc: SCHEME @ MIT-MC
In-Reply-To: <8411120256.AA05811@iuvax.UUCP>
Ok, Will, I'm assuming things decided at the meeting are not cast in
concrete. I certainly take issue with a number of the decisions.
In a few places, I also pick on your notation a bit when I think
its unclear. Thanks for taking the time to write up everything.
Here come the comments...
* I dislike the description of "optional features". In particular,
you say:
Optional features may not be supported by every implementation,
but those that do support a feature will use the same syntax and
semantics for the feature. Hence code that makes use of optional
features will run on any implementation of Scheme that supplies
the optional features.
....
An implementation may extend the language in any way whatsoever,
but code that makes use of extended features is not portable.
These two paragraphs are in conflict and allow for lots of
inconsistency which I will identify at appropriate points later.
The principle troubles, though, are:
* Since a language can be extended in "any way whatsoever",
can such extensions be syntactically in conflict with optional
language features? eg, if #\ is optional and my dialect doesn't
use it, can I then define my own #\ as an extended part of the
required subset?
* In some cases, "required" language features can be redefined
incompatibly by "optional" features. eg,
(COND (FOO => X))
has a well-defined semantics regardless of whether the optional
"=>" feature of COND is present. However, that semantics is not
the same in the two cases.
The point I'm trying to make is that saying something is "optional" says
little if anything unless you at least define that if anyone uses the
syntax corresponding to the optionality in a dialect which doesn't support
the feature, that he is in error. Put another way, extensions may not
invalidate optional features. On the other hand, if this were stipulated
the list of "optional" features to which I objected would be quite lengthy.
* I disagree with calling the string quote character "double quote".
I prefer "doublequote". Since there is a character named "quote", the
phrase "double quote" might designate '' instead of ".
* In discussing what terminates tokens, you should say which of these
characters (presumably all) are also single-character tokens. In
particular, that "((A B)C)" is tokenized
{"(" "(A" " " "B" ")C" ")"}
or {"(" "(" "A" " " "B" ")" "C" ")"}
hangs in the balance. I'm sure no one disagrees, but if you're not going
to be complete about these things, you are sort of wasting your time
just trying to look formal about things.
* I agree with reserving {, [, ], and }, but I would specify that they
may be used as alphabetic according to syntactic escape conventions.
Optionally, the following characters may be delimiters that
terminate symbols:
* What does it mean to say single quote, backquote and sharpsign
may "optionally" terminate tokens? It means expressions
like (JOHN'S COAT) read differently in the different dialects. How
is this distinct from saying "Optionally, the following characters
may be delimiters that do not terminate symbols:"? It only makes
sense to say something is optional if it's going to mean that when
it's present. I bet some dialects treat (JOHN'S COAT) as a two-list
and others treat it as a three-list. Hence, any description of this
relation between dialects can at best say: "The specification takes
no stand on the issue of whether the following delimiters terminate
symbols. Any use of expressions like (JOHN'S COAT) are to be considered
non-portable."
* I would personally prefer if vertical bar had been defined to be
alphabetic, but I am at least happy that it is "not specified" what
its meaning is rather than that it is "optional".
* I strongly oppose the idea of not specifying an escape char for
symbols. You say there is "widespread agreement that ``slashification''
of characters within symbols is a relic that ought to be abandoned."
I am not party to such agreement.
I strongly oppose the idea of eliminating slashification. The Maclisp
conventions of vertical bars made up for the absence of strings. With
their passing, syntactic quoting of lots of chars is very rare, and
in those few cases, I think slashing works fine. It also is a low-cost
mechanism for the printer, since no lookahead is required. Also, it is
uniform with respect to strings, which already use slash for special
chars anyway. Finally, without slash, there would be no way to get
vbars into symbol names, since vbars cannot adequately quote themselves.
On the other hand, slash can work fine in the absence of vbar. So if
one thing is to go as a readsyntax quoter, it should be vbar.
* Will-- Your meta-syntactic use of "..." in a description of what
the "." character does is very confusing.
* Does anyone mind if (. A) is the same as A? It has a certain elegance
to it if you think about it.
(CONS 3 (CONS 2 (CONS 1 0))) => (3 . (2 . (1 . 0))) => (3 2 1 . 0)
(CONS 2 (CONS 1 0)) => (2 . (1 . 0)) => ( 2 1 . 0)
(CONS 1 0) => (1 . 0) => ( 1 . 0)
0 => 0 => ( . 0)
Just a thought.
* I find #!true and #!false to be ugly and visually confusing
with the popular convention of "!" designating something
destructive. It would make more sense for #! to be saved for
something like #. in Common Lisp. I agree #<something>TRUE
is reasonable. I'd have preferred #: for this.
* What does it mean to say:
"Optionally, binary numbers may be written using the #b notation.
Optionally, octal numbers may be written using the #o notation.
Optionally, decimal numbers may be written using the #d notation.
Optionally, hexadecimal numbers may be written using the #x notation."
Presumably this means that dialects not wanting #B, #O, etc. can
use these to mean other things.
* What does it mean to say:
"Optionally, special characters may be written using the #\
notation. If this feature is supported, then the Common Lisp
names for special characters must be supported."
Presumably this means that if I don't want to be able to write special
characters, I can make #\ do something else. In fact, if I want to
use other names than those used by Common Lisp, I can just "not support"
this feature and then "make any extension whatsoever" to my dialect
such that #\ does something completely different, like understand
a different set of character names.
* Was anything decided about whether #!TRUE and #!FALSE would self-evaluate
or whether they required quoting?
* Was anything decided about whether numbers must self-evaluate or
whether a dialect may require quoting?
* Since "optionally, numbers may be written using decimal points and/or
exponents", does this mean that numbers with decimal points are integers
or floating? Does it mean that if I don't support the feature that
I can take the alternate position?
* I notice that the space of symbol names is highly constrained for
the "required subset". A property, however, that should be required
is that within any given dialect, every interned symbol (no matter what
characters it contains) must have a printed representation which is
read-invertable within that dialect. I suspect that all dialects
do this already anyway, but it should be a guaranteed property of the
language since programmers will tend to depend on such things and should
have a guaranteed semantics backing them up.
* What does it mean to make NIL optionally evaluate to the empty list
or optionally evaluate to false. What happens if I make it false and
then try to run my code in another dialect where it's the empty list
and where the two are not the same thing. The definition of optionality
says that code written in the optional subset will run correctly in
another dialect supporting optional features. It doesn't seem to me
like a good idea to optionally define a symbol as able to take on several
values and then be able to write meaningful code.
* It is specified that "the order of evaluation within an application
is not specified". I would prefer "combination" or "expression" to
"application" as a matter of terminology to avoid confusion with the
application that happens in the APPLY function, which doesn't involve
evaluation at all.
* I don't like the name LETREC; I preferred LABELS. Neither is very
suggestive of anything; the latter is at least a real word.
* Will-- I don't like the use of the term "mistake" throughout the report,
at least without defining it formally. In my dialect, it connotes
an unintentional error and it seems to me that if the user
intentionally did the offending thing, it would not be a mistake.
I would say "error" in its place, or define the term "mistake"
formally early on.
* I disagree with the various forms that claim it to be a "mistake"
to use certain return values, allowing some implementations to
signal an error. I don't agree that such errors can ever be
detected at the language level; I would like a formal description
of exactly when it is believed that such an error could be signalled.
The forms in question are: IF, COND, SET!, DEFINE, DEFINE!, CASE,
SET-CAR!, SET-CDR!, and VECTOR-SET!.
* The semantics of (COND (X => Y)) is messy due to optionality as
described earlier.
* Will-- I would name the ... sequences in definitions of things
like LET, COND, etc which use multiple sequences. I realize you
use them right to left, but that could be made more apparent.
Perhaps ..foo.. instead of ...
* I find the name SET! both ugly and redundant. The "!" convention
as originally created by the T people identifies a destructive
variant of an otherwise-non-side-effecting operation. So, for
example, APPEND and APPEND!, etc. Logically, there could be a
CHANGE-CAR and CHANGE-CAR!, one of which was
(LAMBDA (C V) (CONS V (CDR C)))
and the other which was
(LAMBDA (C V) (SET (CAR C) V) C)
In any case, I strongly think that the primitive for assigment
should be SET and not SET!. In fact, since no one likes assignment
anyway, I don't see any reason why anyone should object to just
leaving this undefined in the standard. It would only discourage
people from writing destructive code. But I would be very unhappy
to see T change the name of SET to SET!. Similarly, I strongly
dislike the name SET-CAR! and SET-CDR!.
* The definition of DEFINE refers to the "top-level" definition of
a variable. I don't believe it's established what "top-level" means,
so this definition is pretty muddy. Further, what is the implication
of this definition upon doing (LAMBDA (X) (DEFINE X X))?
I am very discouraged that the (DEFINE (fn . args) ...) syntax isn't
required. This means that any portable code must be ugly, meaning
no one is likely to ever write truly portable code, meaning this
standard is a farce.
* It is silly to require that there be at least one form in a (BEGIN).
It is easy for macros to come up with situations where there are
no forms to put there and as long as the macro's caller doesn't
depend on the value, it shouldn't matter. The return value of a
BEGIN with no forms should just be undefined.
* The fact that (LET* ...) cannot admit an optional name reveals an
asymmetry which I find very distasteful. I suggest that named LET
be left to implementors as an "arbitrary" extension not to be mentioned
in any common subset.
* I would prefer to have REC be called LABEL. Again, at least it's English.
* I don't see any good reason to have DO not bind RETURN. Can someone
elaborate on that?
* The description of DEFINE inside LAMBDA is inconsistent with the
earlier description of DEFINE as creating a toplevel definition.
I think this should be a non-standard extension. I see no reason to
dignify it with any "optional" status.
* The term "top-level binding" is again completely vague in DEFINE!'s
definition.
* The definition of optionality specified that if an optional feature
was present, the dialect should prefer to call it by the "optional"
name. This is somewhat inconsistent with making SEQUENCE an optional
synonym for BEGIN. Since it is not encouraged for use and is not going
to exist in all dialects, is there any sense to including it here?
* The entire section on datatypes is hopelessly muddled. About the only
useful thing said is that anything which is a first class object must
have unlimited extent.
* In the sentence "There is an object which represents both false and
the empty list", I cannot discern whether that means there may/must
be one/two objects filling that description. Shouldn't we say,
"False and the empty list must be represented as first class objects
and that object {may,must} [not] be distinct." or some such.
* Since datatypes are not declared to be disjoint, it isn't necessary
to mention that characters may be represented as numbers, except perhaps
as a footnote to remind the forgetful reader. Strings can be represented
as numbers, too, the way things are written.
* Was there really anyone who thought streams shouldn't be first class
objects? Since datatypes aren't disjoint and such objects could be
indistinguishable from numbers or arrays or whatever, is there really
a reason to care?
* The unary procedure not should be defined to return "a true value if
its argument is false and a false value if its argument is not false."
... rather than "if its argument is true." for the second part.
* I suggest renaming CALL-WITH-CURRENT-CONTINUATION (or CALL/CC) to just
CONTINUE. eg,
(CONTINUE (LAMBDA (C) (IF (FOO) (F C) (G C))))
Anyone else support this?
* By the way, saying the escape procedure has unlimited extent doesn't say
it can be called more than once. Does everyone agree to either stipulate
that or not?
* If "the unary predicate NUMBER? is true of numbers and false of
everything else" and "the unary predicate INTEGER? is true of
integers and false of everything else", I don't suppose this says
much since types are not disjoint and so strings are not necessarily
not numbers and need not necessarily cause INTEGER? or NUMBER? to
return false. Certainly characters needn't yield false from NUMBER?
or probably from INTEGER?. As such, these predicates are of limited
value.
* Of what point is it to make claims about what "almost all implementations"
will do for real numbers? Either they're required to or they aren't.
The rest belongs in some other document.
* I don't agree that allowing generalization of +, -, *, and / to arbitrary
arity is a good idea or even well-defined. eg, the proper generalization
of - to arity 1 is (- 3) => 3, not (- 3) => -3. Hence, specifying that unary
negation is optional is in conflict with specifying that - may be generalized.
* Will-- The discussion of QUOTIENT/REMAINDER and of CONS/CAR/CDR should
use the word "respectively" in the appropriate places. When I first read
that QUOTIENT and REMAINDER return the quotient and remainder, I spent
an unduly long time flipping back pages looking to see if you'd allowed
multiple values before I realized that it was silly for both these functions
to do the same thing or for that same thing to be what it had first looked
to me like they're doing.
* I don't see why MIN/MAX should be restricted from arity 0. They should
just return the smallest and largest representable numbers. I guess as
long as they aren't defined to signal an error in this case, individual
dialects could be extended anyway.
* It should be made explicit whether (= 1 1.0) is defined to work. Note that
this may be tricky since even (= 1.0 1.0) won't necessarily work if the
1.0's were computed rather than read and have different bit patterns that
are too tiny to make a difference on output.
* It is silly to specify that implementations may "optionally" support
numbers that are non-integers. Why not just define that (NUMBER? x)
doesn't imply (INTEGER? x). That definition wouldn't mean that
every number wasn't an integer, it would only mean that every number
wasn't necessarily a number.
Specifying that "almost all implementations" will support this option
is again silly and might in pathological situations be misleading.
* Is the definition of (TRUNCATE x) really correct? It looks like it must
be screwed up on the negative side near 0. eg, (TRUNCATE -0.5) doesn't
have the same sign as 0.5 does it? Or is there a negative 0?
* The meaning of "interning" a symbol should be specified.
* It should be stated explicitly that CAR and CDR of the empty list
is not defined.
* What's this nonsense about pairs being maybe indistinguishable from
vectors of length 2. Is there a good reason for that? It doesn't really
matter since numbers haven't been defined as distinguishable from
strings either, but it somehow offends my sense of aesthetics to see
this note here. Is this due to some problem with Maclisp HUNK2's or
something unrelated?
* In "The following descriptions use the notion of a proper list. The
set of proper lists is the smallest set satisfying:
the empty list is a proper list
a pair x whose CDR is a proper list is a proper list,
provided (MEMQ x (CDR x)) is false."
I think MEMQ isn't the function that you want, but I find it amusing
to see the language defined meta-circularly in this way (since MEMQ
is almost certainly defined to terminate only on proper lists and may
even want to type-check proper-list-ness).
* Is the function LENGTH defined to err or to not return when given
a circular list? What about an otherwise improper (ie, dotted) list?
* The definition of APPEND is poor. It should be defined with NAMED-LAMBDA
for safety in situations where APPEND gets redefined. Also, its text
description is too windy.
* I see no reason for APPEND! to be defined to possibly side-effect
either arg. This may force lots of needless copying in order to write
provably correct programs. I can't imagine a definition of APPEND!
which would want to destructively modify its last argument.
* All these definitions (APPEND, REVERSE, ...) are ugly due to the
silly restrictive version of DEFINE. I certainly wouldn't want my
students programming like that.
* It should be stated in English what happens if LIST-REF and LIST-TAIL
fall off the end. I assume it follows from the definitions of CAR/CDR
that such is a signallable error.
* There should be MEMQ?, MEMV?, and MEMBER? to match MEMQ, MEMV, and
MEMBER. This enhances garbage collection since if these functions
are only being used for truth value, you don't want to hold pointers
to potentially large list structures. Also, it enhances debugging since
if F is a function on booleans, (F (MEMQ X Y)) will receive true/false
rather than a list or false. Ditto for ASSQ?, ASSV?, and ASSOC?.
* You specify no order of evaluation for MAPCAR. I think you mean no
order of "application".
* I dislike the asymmetry between MAPCAR and MAPC.
MAPC has no defined return value, MAPCAR does.
MAPC has defined order of application, MAPCAR does not.
In short, they have nothing really in common other than they type
of their args. I think they should not be named so similarly.
* I oppose the names MAPCAR and MAPC.
T calls these MAP and WALK, respectively.
The generic form of MAPCAR, which is the only thing for which
arbitrary order of application would make sense (since lists are
only sequentially accessible anyway), has no business being called
MAPCAR.
* With respect to the questions about VECTOR->LIST, I think the
right thing to say is that the conses it returns are mutable,
not that the result is necessarily a "new object", since if the
result is the empty list (eg, from an empty vector), I wouldn't
want the implication to be that
(NOT (EQ (VECTOR->LIST #()) (VECTOR->LIST #())))
since it follows from that that more than one false value must
(rather than "may") be possible.
* What happens if VECTOR-REF is out of range?
* VECTOR-SET! is ugly. It should at least be called SET-VECTOR-REF!
for symmetry with the other SET- things. Personally, I hate the
! and would strongly prefer just SET-VECTOR-REF.
* The relation between OBJECT-HASH and the GC should be specified.
Do things get GC'd if no other pointers exist to them? Also, it
might help to distinguish this kind of "hash" from the number that
comes from SXHASH in Maclisp. It took me a second to realize you
weren't talking about that.
------- End undelivered message -------
------- End undelivered message -------
∂07-Dec-84 1342 RPG Slashification
∂07-Dec-84 1327 JAR@MIT-MC Slashification
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 7 Dec 84 13:27:00 PST
Date: 7 December 1984 16:26-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: Slashification
To: KMP @ MIT-MC
cc: SCHEME @ MIT-MC
In-reply-to: Msg of 6 Dec 1984 22:02-EST from Kent M Pitman <KMP>
I think I was the one who suggested that there be neither slashification
nor vertical barring. If you tell the T printer not to use either \ or
| and it comes across a symbol which requires quoting anyhow, it prints
#[Symbol "foo"]. (If you have \ but not |, as in T, you need to have a
way to print the null symbol anyhow; it really does come out as #[Symbol
""] - try it.) If print tables exist or if STRING->SYMBOL accepts any
string whatsoever, then it is necessary to have some way for unusual
symbols to read and print, but there's not really any need to wire down
a special character for the purpose, because e.g. some # syntax could be
used.
Some people wanted to throw away \ in favor of just | ; people didn't
agree when I suggested going with \ but not | ; so we just decided that
the need was unimportant enough that neither syntax was required. I'm
not convinced that there needs to be a defined, portable way to print
unusual symbols, although maybe you could talk me into such a position.
Jonathan
∂09-Dec-84 1252 RPG MIN/MAX, DO/RETURN
∂08-Dec-84 1556 KMP@MIT-MC MIN/MAX, DO/RETURN
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 8 Dec 84 15:56:47 PST
Date: 8 December 1984 18:55-EST
From: Kent M Pitman <KMP @ MIT-MC>
Subject: MIN/MAX, DO/RETURN
To: SCHEME @ MIT-MC
References: Msg of 6 Dec 1984 22:02-EST from Kent M Pitman <KMP@MIT-MC.ARPA>
Jonathan Rees had a good points about a couple of my earlier remarks...
* Making MIN/MAX return smallest/largest representable number would
be infeasible in implementions with bigfloats or bignums. I should
have thought of that. (I must have been thinking too hard about
the flonum case; sorry.) I'll withdraw that suggestion.
* Making DO bind RETURN would have been a bad idea since it would "wire"
the name RETURN. I withdraw my disparaging remarks about its not binding
that name.
-kmp
∂09-Dec-84 1304 RPG Re: critique of preliminary report
∂09-Dec-84 1142 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa Re: critique of preliminary report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Dec 84 11:42:25 PST
Received: from indiana by csnet-relay.csnet id a022287; 9 Dec 84 14:34 EST
Received: by iuvax.UUCP (4.12/4.7)
id AA06716; Sat, 8 Dec 84 22:50:32 est
Date: Sat, 8 Dec 84 22:50:32 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
To: KMP@mit-mc.ARPA
Subject: Re: critique of preliminary report
Cc: scheme@mit-mc.ARPA
I am posting this in response to Kent Pitman's excellent critique
of the preliminary report on the October workshop.
ERRORS AND OVERSIGHTS
I should have said:
Numbers, strings, characters, and #!TRUE and #!FALSE are
self-evaluating, which means they need not be quoted. Symbols and
pairs are not self-evaluating. It is not specified whether other
things are self-evaluating.
The semantics of (BEGIN) is not specified.
TRUNCATE could be defined by
(DEFINE TRUNCATE
(LAMBDA (X)
(IF (NEGATIVE? X)
(- 0 (FLOOR (ABS X)))
(FLOOR X))))
VECTOR-REF takes a vector v and an nonnegative integer n such
that n < (VECTOR-LENGTH v) and returns ... .
----------------------------------------------------------------
WHAT DOES "OPTIONAL" MEAN?
The intent of the workshop was that extensions must not conflict
with optional features, and I should have said so. In fact some
features were made optional in order to prevent dialects from
using certain syntaxes for other purposes. It follows that #b,
#o, #d, #x, #\, and so on can't be used for any purpose other
than to support the optional feature.
I agree that the "optional" stuff about NIL and T is ridiculous.
What I should have said instead is that implementations that want
to treat NIL and T as constants can do so. In effect this is a
warning against using NIL and T to name variables. Note that
(FOO . NIL) cannot read the same as (FOO) no matter what.
I didn't mean to say that "optional" names or features are to be
preferred to essential names or features, and I don't think I did.
----------------------------------------------------------------
POOR WRITING IN THE PRELIMINARY REPORT
I agree with Kent Pitman's points regarding the use of "...",
"mistake", "respectively", and "double quote".
I agree that the set of single character tokens needs to be
better defined. I would like to include appendixes in the final
report with more rigorous descriptions of the lexical syntax, the
context-free syntax, and the denotational semantics of Scheme.
How about "The order of evaluation within a procedure call is not
specified"? That isn't quite true, of course -- normal order
evaluation is prohibited.
I should have said that some single object represents both false
and the empty list. There may be other objects representing
false. Might there be other objects representing the empty list?
(I hope not.)
I agree that it would be better to have said that (NUMBER? x)
doesn't imply (INTEGER? x).
I hope everyone noticed that it is an error to take the CAR or
CDR of the empty list.
The definition of a proper list in the preliminary manual was a
joke. The notion of a proper list has to do with finiteness,
which is not first order definable.
----------------------------------------------------------------
LEXICAL MATTERS
It is not specified whether single quote, backquote, sharp sign,
and vertical bar are delimiters that terminate symbols. The
status of these characters would be decided by a general rule
that emerged during discussion at the workshop, but not everyone
agreed to the general rule. The general rule is: Special
characters that come in pairs (left and right parenthesis, left
and right bracket, left and right curly brace, doublequote)
should be delimiters while other special characters (period and
so on) should be preceded by a space if they are to be used in
their special sense. Semicolon isn't really an exception to the
pattern because the end of line would be a delimiter anyway.
Whether vertical bar should be a delimiter according to the rule
depends on whether vertical bar is a special character that comes
in pairs, which is not specified. According to the rule single
quote, backquote, and sharp sign should not be delimiters.
> * I agree with reserving {, [, ], and }, but I would specify that they
> may be used as alphabetic according to syntactic escape conventions.
I don't understand "...according to syntactic escape conventions".
I have yet to hear of a good use for slashification of symbols.
If there is no compelling need for a feature, we should leave it
out. The workshop allowed slashification but did not encourage
it.
> * I notice that the space of symbol names is highly constrained for
> the "required subset". A property, however, that should be required
> is that within any given dialect, every interned symbol (no matter what
> characters it contains) must have a printed representation which is
> read-invertable within that dialect. I suspect that all dialects
> do this already anyway, but it should be a guaranteed property of the
> language since programmers will tend to depend on such things and should
> have a guaranteed semantics backing them up.
We probably ought to require something along these lines, but the
property you desire is too strong. It is enough that every
symbol read by the reader be printed in a form that will read
back in as the same symbol. Other symbols are too random to
worry about. In fact, I would be satisfied if only the required
set of symbol names have the property you desire. For what it's
worth, Franz Lisp does not have the property, but I doubt that
its lack is a significant cause of dissatisfaction with Franz
Lisp.
----------------------------------------------------------------
SPECIAL FORMS
LETREC vs LABELS, REC vs LABEL, and SET vs SET! are matters of
taste that needed to be decided one way or the other, and were.
History plays a significant role in decisions such as these. The
first two matters had history on both sides, but the history of
SET in traditional Lisp counts against it.
In some cases the IF, COND, and CASE special forms return
unspecified values. The SET!, DEFINE, and DEFINE! special forms,
and the SET-CAR!, SET-CDR!, and VECTOR-SET! procedures, always
return unspecified values. Except for the result of the DEFINE
form, I wrote that it is a "mistake" to use these undefined
values, and except for the results of the DEFINE and DEFINE!
forms I wrote that implementations could signal an error if the
values that were returned were "used". What I wrote is faithful
to the workshop's decisions, but I can be accused of deviating in
the cases of DEFINE and DEFINE! .
Kent is right to question what we meant by "using" a value. The
answer is that we don't know. Obviously an implementation could
return a strange value that would cause an error to be signalled
if an attempt were ever made to take its CAR or its successor; an
implementation could also arrange for an error to be signalled if
the value were ever an operand to EQ? or CONS; and there are no
doubt other things that an implementation could do as well. I
will not offer a formal description of the circumstances under
which an error could be signalled, because I want to leave room
for implementations to experiment with different approaches.
A DEFINE form is at "top level" iff it it not nested within any
other form. This definition clearly establishes circumstances
that do not count as top level, but it does not establish any
circumstances that do count as top level. I think each
implementation will have to specify circumstances under which a
DEFINE form has the described semantics, and those circumstances
would then count as top level for that implementation.
The Abelson and Sussman book uses DEFINE inside LAMBDA as
syntactic sugar. Scheme's future is tied to the success of that
book, so the sugar was dignified with "optional" status. The
optional status of the sugar required that ordinary DEFINE be
restricted to "top level".
The (DEFINE (fn . args) . body) sugar was dignified with
"optional" status for the same reason. Kent has acquired a taste
for this sugar, but I consider it a violation of orthogonality
that is doubly pernicious: (1) it discourages programmers from
thinking of procedures as objects distinct from their names; (2)
it discourages programmers from using procedures with local
state.
I agree that the optional status of named LET should imply an
optional status for named LET*, or else both named LET and named
LET* should be left out altogether. By the way, David Bartley
asks whether the body of a named let is within the scope of the
name. The Revised Report has the body within the scope of the
name. Does anyone want to argue that the body should be outside
the scope of the name?
When it was asked if DO should bind RETURN, someone said "Of
course not!", and that was the end of the discussion. If DO were
to bind RETURN I believe that DO would be the only construct in
even the optional language to bind an identifier that does not
appear explicitly in the code, and I see no reason to condone
that kind of anomaly.
----------------------------------------------------------------
DATATYPES
I was disappointed that we were unable to agree that any
datatypes were disjoint. The fact that the workshop participants
insisted on a special note to the effect that characters need not
be a distinguishable data type leads me to believe that despite
their votes most participants assumed that other data types were
distinguishable. In the final report I intend to recommend that
at the very least numbers, symbols, and pairs should be disjoint;
does anyone object?
Even without disjointness of data types, the NUMBER? and INTEGER?
predicates are useful because they define the domains of other
procedures. Thus if all strings are numbers then it must be
possible to subtract strings.
The nonsense to the effect that pairs might be indistinguishable
from vectors of length 2 is to remind folks not to assume that
pairs and vectors are disjoint. I agree that the note is out of
place and ugly.
I expect streams will be a Scheme data type, but as Kent points
out they might overlap with (say) numbers. Nonetheless the
STREAM? predicate will be useful because anything of which the
STREAM? predicate is true will have to support the operations on
streams.
----------------------------------------------------------------
PROCEDURES
I think it went without saying that escape procedures can be
called more than once. We didn't feel any need to say that the
addition procedure could be called more than once, either.
The generalizations of +, -, *, and / to arbitrary arity must
follow Common Lisp, so the ambiguity is not great. There is some
ambiguity, however, because Common Lisp has all sorts of rules
about integers, rationals, floats, and complexes that don't apply
to Scheme.
MIN and MAX are restricted from arity 0 because some
implementations don't have a smallest or largest representable
number.
Implementations should not be allowed to signal an error on
something like (=? 1 1.0). I don't think we should specify that
the result is true because you might want to implement a Scheme
in which "approximations" are a subtype of the numbers, in which
1.0 is read in as an approximation, and in which all equality
comparisons involving approximate numbers return false.
(If you haven't caught on by now, I'm perfectly comfortable with
the fact that Scheme is far less tightly specified than Common
Lisp. I believe Scheme can continue to represent the future of
Lisp only by being open to experimentation.)
I would rather not talk about "interning" a symbol, because
there is no need to talk about it when all symbols are interned.
I have to use words like "interned" to talk about implementations
in which not all symbols are interned, but for definitions I
would like to refer people to manuals for traditional Lisps.
LENGTH is defined on proper lists, and its action on anything
else is not specified.
I can't imagine a definition of APPEND! that would want to mutate
its last argument either. Shall we say it doesn't?
Kent's suggestions for MEMQ?, MEMV?, MEMBER?, ASSQ?, ASSV?, and
ASSOC? are interesting. Several people at the workshop, notably
Hal Abelson, expressed the belief that we ought to reconsider the
entire MEMBER/ASSOC complex of procedures.
MAPCAR and MAPC have their historical names for historical
reasons, and I would not be averse to renaming them eventually.
If MAPCAR is defined as follows in an implementation that
evaluates right to left, then the list of results is constructed
from right to left:
(DEFINE MAPCAR
(LAMBDA (F L)
(IF (NULL? L)
'()
(CONS (F (CAR L)) (MAPCAR F (CDR L))))))
I agree with Kent that the result of VECTOR->LIST cannot
reasonably be guaranteed to be a new object.
VECTOR-SET!, SET-CAR!, and SET-CDR! seem inconsistent to me too.
I think we should offer a prize for the best rationalization of
these names.
I think garbage collection should be treated as an issue of
performance rather than as an issue of semantics.
Peace, William Clinger
∂09-Dec-84 1307 RPG apology to Franz Lisp
∂09-Dec-84 1145 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa apology to Franz Lisp
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Dec 84 11:44:54 PST
Received: from indiana by csnet-relay.csnet id ab22287; 9 Dec 84 14:36 EST
Received: by iuvax.UUCP (4.12/4.7)
id AA01074; Sun, 9 Dec 84 11:11:13 est
Date: Sun, 9 Dec 84 11:11:13 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
To: scheme@mit-mc.ARPA
Subject: apology to Franz Lisp
I apologize to Franz Lisp for claiming that not every interned symbol in
Franz has a printed representation that reads back in as the same symbol.
An example confused me but not Franz Lisp.
Peace, William Clinger
∂10-Dec-84 1123 RPG Scheme conference report
∂09-Dec-84 1648 @MIT-MC:ANDY@SU-SCORE.ARPA Scheme conference report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Dec 84 16:48:24 PST
Date: Sun 9 Dec 84 16:45:14-PST
From: Andy Freeman <ANDY@SU-SCORE.ARPA>
Subject: Scheme conference report
To: scheme@MIT-MC.ARPA
Will the final report on the scheme conference say anything about
macros? There are substantial issues to be resolved/understood,
especially in scoping and expansion, but can a "least common
denominator" solution be released in the interim? How about a syntax
for defining top-level macros? That can be useful even if everything
else is undefined or optional.
Speaking of top-level solutions, why was ",." left out of the
backquote syntax? (It's like ",@", except that the value of the
following form may be destructively spliced into the result. ",@", as
you recall, non-destructively splices the value of the following form
into the result.) If deeper levels of nesting are going to be
optional, the report has to define what happens.
By the way, unless Scheme is going to define a character set, EOF
isn't necessarily a character. Neither is end-of-line.
Are all symbols interned or not? (Interning isn't necessary to print
code and be able to read it back in later.)
Still, most of these are minor issues. What the final report really
needs is a discussion of the decisions. Some things do not need
explanation (except to historians), like the names lambda and ', but,
for instance, why are true and false self-evaluating? In many cases
the decision itself is unimportant, but the issues are.
The report would also be improved by explicit mention of controversial
issues. So there's no decision; the reasons are still important.
-andy
ps - Why is argument evaluation order unspecified? That was a mistake
in Pascal, but then AND/OR/etc. have a defined order in Scheme. Then
again, so many standard forms have a right-left defined order that
consistency would suggest that user procedures should also.
Is the closure position an argument?
-------
∂10-Dec-84 1137 RPG Scheme conference report
∂09-Dec-84 1648 @MIT-MC:ANDY@SU-SCORE.ARPA Scheme conference report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Dec 84 16:48:24 PST
Date: Sun 9 Dec 84 16:45:14-PST
From: Andy Freeman <ANDY@SU-SCORE.ARPA>
Subject: Scheme conference report
To: scheme@MIT-MC.ARPA
Will the final report on the scheme conference say anything about
macros? There are substantial issues to be resolved/understood,
especially in scoping and expansion, but can a "least common
denominator" solution be released in the interim? How about a syntax
for defining top-level macros? That can be useful even if everything
else is undefined or optional.
Speaking of top-level solutions, why was ",." left out of the
backquote syntax? (It's like ",@", except that the value of the
following form may be destructively spliced into the result. ",@", as
you recall, non-destructively splices the value of the following form
into the result.) If deeper levels of nesting are going to be
optional, the report has to define what happens.
By the way, unless Scheme is going to define a character set, EOF
isn't necessarily a character. Neither is end-of-line.
Are all symbols interned or not? (Interning isn't necessary to print
code and be able to read it back in later.)
Still, most of these are minor issues. What the final report really
needs is a discussion of the decisions. Some things do not need
explanation (except to historians), like the names lambda and ', but,
for instance, why are true and false self-evaluating? In many cases
the decision itself is unimportant, but the issues are.
The report would also be improved by explicit mention of controversial
issues. So there's no decision; the reasons are still important.
-andy
ps - Why is argument evaluation order unspecified? That was a mistake
in Pascal, but then AND/OR/etc. have a defined order in Scheme. Then
again, so many standard forms have a right-left defined order that
consistency would suggest that user procedures should also.
Is the closure position an argument?
-------
∂10-Dec-84 1142 RPG Scheme conference report
∂10-Dec-84 0930 @MIT-MC:JINX@MIT-OZ Scheme conference report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 10 Dec 84 09:30:02 PST
Date: 10 Dec 1984 12:24 EST (Mon)
Message-ID: <JINX.12070348515.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Andy Freeman <ANDY@SU-SCORE.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: Scheme conference report
I would like to clarify (hopefully) a few points with respect
to the evaluation of combinations:
The operator position is a "distinguished" argument. In my
opinion it is the only position for which the evaluation order might
be relevant. If reflective procedures are present in an
implementation, then the operator position must be evaluated before
any operand expressions. Since in the common subset there is no
provision for reflective procedures, there is no need to specify any
particular order with respect to the operator.
In Will's last message there was a statement to the effect
that normal order evaluation was prohibited. I find this rather
surprising. One of Guy Steele's Rabbit compiler main points was that
normal order beta-subtitution could be used very successfully to
optimize Scheme code. In the absence of side-effects, and if the
programs terminate when using applicative order, there is no way to
determine whether normal or applicative order is used. A compiler can
use this profitably to postpone evaluation. A think that a more
appropriate statement is that portable programs should not depend on
the evaluation strategy used, ie. they should work in applicative
order, but different implementations may want to use different
strategies.
The order of argument evaluation was left unspecified for
various reasons:
- The order of argument evaluation is only relevant in the
presence of side-effects in some of the argument expressions. Scheme
is predominantly an applicative language (contrast with Pascal), and
good style requires that arguments to procedures (operands of
combinations) be side-effect free. By not specifying the order, it
was felt that code with such side-effects would be discouraged since
its effect would not be predictable.
- An optimizing compiler can do a better job if it has freedom
over the order in which it can execute expressions. Leaving the order
unspecified potentially allows a clever compiler to choose the optimal
order for each combination. Note that the meaning of a program can
only be changed by reordering if the argument expressions contain
side-effects. But this code could not be guaranteed to work in other
implementations with different default order for argument evaluation.
- Leaving the order of argument evaluation unspecified allows
a parallel implementation to evaluate in parallel. Note again that
the only programs whose semantics are not clear (and are therefore not
predictable) are those with side-effects in the operands of a
combination.
A marginally related issue is the issue of macros. In Scheme
there is not so much of a need to provide a macro facility as in other
dialects of Lisp. Macros are needed only to provide "nicer", more
readable syntax. In other dialects they are needed to extend the
langauge since there is no way of encapsulating an expression and an
environment. Freezing ("thunkifying", wrapping in a lambda
expression) an argument encapsulates a context and an expression in a
procedure which can then be invoked at will by the operator procedure.
While syntactically clumsy, it is conceptually very elegant. Note
that an optimizing compiler (Rabbit, for example) can eliminate most
or all of the overhead of freezing and thawing.
∂12-Dec-84 1711 RPG Re: Scheme conference report
∂12-Dec-84 1601 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Re: Scheme conference report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 12 Dec 84 16:01:03 PST
Received: from unc by csnet-relay.csnet id aa04450; 12 Dec 84 15:04 EST
Received: by unc (4.12/4.7) id AA29958; Tue, 11 Dec 84 00:04:48 est
Date: Tue, 11 Dec 84 00:04:48 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8412110504.AA29958@unc>
To: ANDY@su-score.ARPA, scheme@mit-mc.ARPA
Subject: Re: Scheme conference report
Relative order of evaluation of the expressions in a combination is
not specified for at least two reasons:
1) It is poor coding style to depend on order of evaluation. If
there is an ordering constraint it should be made explicit
by using "let" or some such.
2) It is a severe constraint on the implementation for the language
to specify an evaluation order. What is easy for one machine
model or architecture may be difficult for another.
Note that Pascal and Scheme are not alone; neither C nor Common Lisp
specify the order of evaluation.
Kent Dybvig
∂12-Dec-84 1847 RPG
∂12-Dec-84 1837 KMP@MIT-MC
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 12 Dec 84 18:37:11 PST
Date: 12 December 1984 21:37-EST
From: Kent M Pitman <KMP @ MIT-MC>
To: dyb%unc.csnet @ CSNET-RELAY
cc: SCHEME @ MIT-MC
Actually, Common Lisp does specify the order of evaluation as left to right.
It's tricky to find the passages in the CL manual which assure this, but
they are there if you look hard enough. The issue came up recently in the
Common Lisp discussion group and subsided after various obscure but recently
conclusive passages were cited.
Anyway, I agree it is reasonable to leave the order unspecified. It may be
computationally infeasible for the compiler to determine when order of
evaluation matters in many situations where "better code" would be available
if such a determination could be made.
∂15-Dec-84 2257 RPG Scheme bibliography
∂15-Dec-84 1655 @MIT-MC:CPH@MIT-OZ Scheme bibliography
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 15 Dec 84 16:55:16 PST
Date: Sat, 15 Dec 1984 19:53 EST
Message-ID: <CPH.12071740976.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: linus!ramsdell%UUCP@YALE.ARPA (John D. Ramsdell)
Cc: T-Discussion%MIT-OZ@MIT-MC.ARPA, Scheme@MIT-MC
Subject: Scheme bibliography
In-reply-to: Msg of 14 Dec 1984 13:44-EST
Fri 14 Dec 84 09:26:47 est from linus!ramsdell at Mitre-Bedford,
linus!ramsdell%UUCP at YALE.ARPA (John D. Ramsdell)
I believe that this is a complete list of the early Scheme papers:
Steele, Guy Lewis, Jr., and Gerald Jay Sussman. 1975. Scheme: An
interpreter for the extended lambda calculus. Memo 349, MIT
Artificial Intelligence Laboratory.
Steele, Guy Lewis, Jr., and Gerald Jay Sussman. 1976. Lambda: The
ultimate imperative. Memo 353, MIT Artificial Intelligence
Laboratory.
Steele, Guy Lewis, Jr. 1976. Lambda: The ultimate declarative. Memo
379, MIT Artificial Intelligence Laboratory.
Steele, Guy Lewis, Jr. 1977. Debunking the "expensive procedure
call" myth. In Proceedings of the National Conference of the ACM, pp.
153-62.
Steele, Guy Lewis, Jr., and Gerald Jay Sussman. January 1978. The
revised report on Scheme: A dialect of Lisp. Memo 452, MIT Artificial
Intelligence Laboratory.
Sussman, Gerald Jay, and Guy Lewis Steele, Jr. May 1978. The art of
the interpreter or, The modularity complex. Memo 452, MIT Artificial
Intelligence Laboratory.
Steele, Guy Lewis, Jr. May 1978. Rabbit: A compiler for Scheme.
Technical report 474, MIT Artificial Intelligence Laboratory.
∂16-Dec-84 2313 RPG continuation terminology
∂16-Dec-84 2039 @MIT-MC:cth%indiana.csnet@csnet-relay.arpa continuation terminology
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 16 Dec 84 20:39:11 PST
Received: from indiana by csnet-relay.csnet id a001364; 16 Dec 84 23:35 EST
Received: by iuvax.UUCP (4.12/4.7)
id AA04292; Sun, 16 Dec 84 17:27:40 est
Date: Sun, 16 Dec 84 17:27:40 est
From: Chris Haynes <cth%indiana.csnet@csnet-relay.arpa>
To: scheme@mit-mc.ARPA
Subject: continuation terminology
We object strongly to the use of the term "escape procedure". The word
"escape" is far to limiting to describe continuations, which are good for so
much more. Also, the term "escape procedure" is strongly associated with the
limited facility by that name provided by most Lisp systems (which isn't good
for much besides "escaping"). If we adopt the old Lisp name, many will
assume that continuations aren't good for anything more than Lisp escape
procedures, and will miss what we feel is one of the most important
distinguishing features of Scheme.
We find the term "continuation" to be quit satisfactory in most contexts, and
it agrees with the name "call-with-current-continuation". However, we
recognize that in the context of denotational semantics or implementation
discussions, there is possibility of confusing continuations as first-class
programming objects and their semantic or implementation counterparts. Thus
additional terminology is desirable when such distinctions must be made, and
to standardize such terminology it should probably be used in the Revised
Revised Report. We suggest the term "continuation object" for this purpose,
though it is not wonderful and we welcome other suggestions.
-- Chris Haynes
Dan Friedman
Eugene Kohlbecker
∂17-Dec-84 1524 RPG continuation terminology
∂17-Dec-84 1523 JAR@MIT-MC continuation terminology
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 17 Dec 84 15:23:41 PST
Date: 17 December 1984 18:23-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: continuation terminology
To: cth%indiana.csnet @ CSNET-RELAY
cc: SCHEME @ MIT-MC
In-reply-to: Msg of Sun 16 Dec 84 17:27:40 est from Chris Haynes <cth%indiana.csnet at csnet-relay.arpa>
Date: Sun, 16 Dec 84 17:27:40 est
From: Chris Haynes <cth%indiana.csnet at csnet-relay.arpa>
We object strongly to the use of the term "escape procedure"...
My only objection to the terms "continuation" and "continuation object"
is that the presence of fluids and/or UNWIND-PROTECT mean that the thing
created by the user-visible CATCH or CONTINUE or CALL-... or whatever is
more than just a continuation, since it implicitly includes a reference
to the dynamic state. There is a low-level thing which really does give
you a continuation, but I expect that the mechanism which does the right
thing with fluids would be the normal one used by users.
I don't have any new alternative term to propose, however.
Of course, we decided not to decide whether or not the essential
scheme's continuation procuration combinator dealt properly with fluids,
since essential scheme doesn't deal with fluids at all. It seems to me
that any fluid mechanism whatsoever must distinguish between
continuations and continuation+state things. As things are, my guess is
that it would be up to the implementor which of these two things the
essential dialect's CALL-... gives you. (This might be the wrong thing,
but I won't argue that position here - this message is already too long.)
(By the way, no Lisp has never had escape procedures per se; the usual
CATCH/THROW mechanism doesn't introduce a new kind of object. I'm not
convinced that the term "escape procedure" is as broken as you think it
is, or that it necessarily has such strong connotations. But I'm not
partial to the term.)
∂18-Dec-84 2009 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Common Lisp order of evaluation
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 18 Dec 84 20:09:07 PST
Received: from unc by csnet-relay.csnet id ac00691; 18 Dec 84 14:57 EST
Received: by unc (4.12/4.7) id AA12698; Fri, 14 Dec 84 10:29:23 est
Date: Fri, 14 Dec 84 10:29:23 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8412141529.AA12698@unc>
To: KMP@mit-mc.ARPA, SCHEME@mit-mc.ARPA
Subject: Common Lisp order of evaluation
If you have found passages which indicate a specific order of
evaluation, I'd like to know about it. All that I have found
in scouring the manual several times over, in several different
versions over the years, is that arguments are 'processed' in
left-right order *once they reach the caller*. Regardless of
any intentions on the designer's part, or any decisions of
discussion groups, any feature of the language that is not
spelled out is subject to interpretation. There is certainly
nowhere in the manual that states that arguments are evaluated
in left-right order.
∂19-Dec-84 0850 @MIT-MC:rhh@MIT-VAX Re: Common Lisp order of evaluation
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 19 Dec 84 08:49:55 PST
Received: by mit-vax.Mit-chaos.Arpa (4.12/4.8) id AA25785; Wed, 19 Dec 84 11:40:26 est
Date: Wed, 19 Dec 84 11:40:26 est
From: Bert Halstead <rhh@mit-vax>
To: KMP@mit-mc.ARPA, SCHEME@mit-mc.ARPA, dyb%unc.csnet@csnet-relay.arpa
Subject: Re: Common Lisp order of evaluation
The following passages out of the Common Lisp book may be relevant:
"setf carefully arranges to preserve the usual left-to-right order
in which the various subforms are evaluated." (p. 97)
"Macros that manipulate generalized variables must guarantee the
'obvious' semantics: subforms of generalized-variable references
are evaluated exactly as many times as they appear in the source
program, and they are evaluated in the same order as they appear
in the source program." (p. 99)
-Bert
∂19-Dec-84 0912 @MIT-MC:CPH@MIT-OZ Common Lisp order of evaluation
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 19 Dec 84 09:12:05 PST
Date: Wed, 19 Dec 1984 12:12 EST
Message-ID: <CPH.12072705547.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Scheme@MIT-MC
Subject: Common Lisp order of evaluation
In-reply-to: Msg of 19 Dec 1984 11:40-EST from Bert Halstead <rhh at mit-vax>
Come on, folks... This really isn't a great place to argue about what
order Common Lisp evaluates its arguments. I for one don't care and
would rather not know.
∂23-Dec-84 0901 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa length vs. list-length
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 23 Dec 84 09:00:57 PST
Received: from unc by csnet-relay.csnet id ag24249; 23 Dec 84 11:49 EST
Received: by unc (4.12/4.7) id AA29885; Sun, 23 Dec 84 01:06:25 est
Date: Sun, 23 Dec 84 01:06:25 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8412230606.AA29885@unc>
To: scheme@mit-mc.ARPA
Subject: length vs. list-length
My primary concern about the length function seems to have been
lost in the ensuing discussions. I do not insist that Scheme
have a generic length function. I do insist that the naming
convention for such functions be consistent.
Doesn't this look a little odd?
(define generic-length
(lambda (x)
(cond ((string? x) (string-length x))
((vector? x) (vector-length x))
((list? x) (length x)))))
I like this much better:
(define generic-length
(lambda (x)
(cond ((string? x) (string-length x))
((vector? x) (vector-length x))
((list? x) (list-length x)))))
We have list-ref, vector-ref and string-ref. Why should we not
have list-length rather than length? While we're at it, why
not have list-append rather than append? Any functions that makes
sense for strings, lists, and vectors should be named with
the appropriate type-name prefix. (Even though the language
doesn't specify a reverse function for vectors or strings
and since such functions would be reasonable, the reverse
function for lists should be named list-reverse.)
∂23-Dec-84 2330 @MIT-MC:mw%brandeis.csnet@csnet-relay.arpa list-length
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 23 Dec 84 23:30:17 PST
Received: from brandeis by csnet-relay.csnet id a026028; 24 Dec 84 2:15 EST
Received: by brandeis.ARPA (4.12/)
id AA06312; Sun, 23 Dec 84 22:31:44 est
Date: 23 Dec 1984 22:30-EST
From: mw%brandeis.csnet@csnet-relay.arpa
In-Real-Life: Mitchell Wand,faculty
Subject: list-length
To: scheme@mit-mc.ARPA
Cc: dyb%unc.csnet@csnet-relay.arpa
Message-Id: <472707016/mw@brandeis>
I vote for list-length over length, too. I think we just went over
that one a little too rapidly at the meeting.
-- Mitch Wand
∂24-Dec-84 1350 @MIT-MC:mw%brandeis.csnet@csnet-relay.arpa list-length
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 24 Dec 84 13:50:48 PST
Received: from brandeis by csnet-relay.csnet id a026028; 24 Dec 84 2:15 EST
Received: by brandeis.ARPA (4.12/)
id AA06312; Sun, 23 Dec 84 22:31:44 est
Date: 23 Dec 1984 22:30-EST
From: mw%brandeis.csnet@csnet-relay.arpa
In-Real-Life: Mitchell Wand,faculty
Subject: list-length
To: scheme@mit-mc.ARPA
Cc: dyb%unc.csnet@csnet-relay.arpa
Message-Id: <472707016/mw@brandeis>
I vote for list-length over length, too. I think we just went over
that one a little too rapidly at the meeting.
-- Mitch Wand
∂28-Dec-84 1428 JAR@MIT-MC list-length
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 28 Dec 84 14:28:26 PST
Date: 28 December 1984 17:29-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: list-length
To: SCHEME @ MIT-MC
In-reply-to: Msg of 23 Dec 1984 22:30-EST from mw%brandeis.csnet at csnet-relay.arpa
LIST-APPEND, LIST-REVERSE, LIST-SORT, LIST-MAPCAR, ...
∂13-Jan-85 1322 JAR@MIT-MC list-length
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 13 Jan 85 13:21:53 PST
Date: 13 January 1985 16:22-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: list-length
To: willc%indiana.csnet @ CSNET-RELAY
cc: SCHEME @ MIT-MC
In-reply-to: Msg of Fri 4 Jan 85 15:50:17 est from Will Clinger <willc%indiana.csnet at csnet-relay.arpa>
Date: Fri, 4 Jan 85 15:50:17 est
From: Will Clinger <willc%indiana.csnet at csnet-relay.arpa>
Pardon me, but I am not certain whether your recent message (LIST-APPEND,
LIST-REVERSE, LIST-SORT, LIST-MAPCAR, ...) was in support of or in derision
of the proposal that the operations on lists be prefixed by LIST- .
Neither, really. The intent of the message was to ask "where do you
draw the line?". E.g. APPEND / STRING-APPEND have the same problem that
LENGTH / STRING-LENGTH do. If you're not careful you end up putting
data type prefixes on everything (as you might have to in a strongly typed
language without unions, like PASCAL) or nothing (as in a fully generic
language like Smalltalk). What policy should we adopt?
∂13-Jan-85 1328 KMP@MIT-MC policy to adopt
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 13 Jan 85 13:28:24 PST
Date: 13 January 1985 16:28-EST
From: Kent M Pitman <KMP @ MIT-MC>
Subject: policy to adopt
To: SCHEME @ MIT-MC
i think we should clearly re-emphasize what our rationale is for wanting
any standard before deciding a policy. if the only purpose is to be able
to write papers that use common syntax, the policy might want to be different
than if we plan to port code. as much as we are not trying to make a
Common Scheme, some of the trends in this discussion have leaned pretty
strongly in that direction, perhaps overly so in some cases. i can elaborate
if it becomes appropriate to do so; i'll let it go at that for now.
-kmp
∂13-Jan-85 2117 @MIT-MC:CPH@MIT-OZ Scheme String Operations: the Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 13 Jan 85 21:17:18 PST
Date: Mon, 14 Jan 1985 00:17 EST
Message-ID: <CPH.12079391220.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: David Bartley <Bartley%ti-csl.csnet@CSNET-RELAY.ARPA>,
Jensen%ti-csl.csnet@CSNET-RELAY.ARPA,
Oxley%ti-csl.csnet@CSNET-RELAY.ARPA, Scheme@MIT-MC
Subject: Scheme String Operations: the Report
In-reply-to: Msg of 13 Jan 1985 15:14-EST from CPH
Here is the preliminary report... Comments and suggestions?
----------------------------------------------------------------------
Scheme String Operations
Notes:
[] Strings are mutable vectors of characters.
[] The string datatype described here has very little dependence on
the character datatype from which it is built. Thus it may correspond
to either of Common Lisp's STRING or SIMPLE-STRING datatypes. In MIT
Scheme, the character datatype is a special extended ASCII.
[] Historically, two different methods have been used to specify
substrings: [1] a starting index and a length, and [2] a starting
index and an ending index. Often both methods have been used for
different operations in the same data abstraction.
The arguments in favor of one method or the other seem fairly
uninteresting, but it does seem important to pick one method and use
it exclusively. The latter method has been chosen, for no
particularly good reason.
Naming conventions:
[] Character-wise operations are normally specified in two forms, one
which operates on a substring, and another which operates on an entire
string. The former is usually named "SUBSTRING-..." and the latter
"STRING-...".
[] Operations for which case sensitivity has meaning are specified in
two forms, a case-sensitive version and a case-insensitive version.
The latter is given the suffix "-CI" to distinguish it; if the
operation is a predicate, the suffix precedes the "?" at the end of
the name.
[] Currently, operation pairs which are "directed" will be given
similar names, such as, "STRING-FIND-NEXT-CHAR" and
"STRING-FIND-PREVIOUS-CHAR". However, there are 3 different syllable
pairs used to distinguish these operations: "LEFT"/"RIGHT",
"PREVIOUS"/"NEXT", and "FORWARD"/"BACKWARD". In each case the
particular pair was chosen for its meaning, but it may be better to
name them more consistently.
!
----------------------------------------------------------------------
Definitions
[] The phrases "X is a string" and "the string X" mean that X is an
object which satisfies the STRING? predicate. Similarly, "X is a
character" means that X satisfies the CHAR? predicate.
[] The "length" of a string is the number of characters that it
contains. This number is a non-negative integer that is determined at
the time of the string's creation.
[] The phrase "X is a valid index of Y", where Y is a string, means
that X is a non-negative integer that is strictly less than the length
of Y. The index 0 refers to the first character, 1 to the second,
etc.
[] The phrase "<X,Y,Z> is a substring" means that:
1. X is a string.
2. Both Y and Z are non-negative integers.
3. Z is less than or equal to the length of X.
4. Y is less than or equal to Z.
This refers to that substring of X starting at Y (inclusive) and
ending at Z (exclusive). If Y is equal to Z, the substring is empty.
[] The directions "left" and "right" refer to numerically decreasing
and numerically increasing indices, respectively. Alternate names for
these directions are (respectively): "previous" and "next"; "backward"
and "forward".
!
----------------------------------------------------------------------
Basic Character Operations
These are the operations on characters that are required by the string
data abstraction. The names of these operations are irrelevant; only
the functionality is required.
(CHAR-EQUAL? CHAR1 CHAR2)
(CHAR-EQUAL-CI? CHAR1 CHAR2)
These predicates are true iff CHAR1 and CHAR2 are the same character.
The former operation is case sensitive, while the latter is not. Both
CHAR1 and CHAR2 must be characters.
(CHAR-LESS? CHAR1 CHAR2)
(CHAR-LESS-CI? CHAR1 CHAR2)
These predicates are true iff CHAR1 is strictly less than CHAR2 in the
character ordering. The former operation is case sensitive, while the
latter is not. Both CHAR1 and CHAR2 must be characters.
(CHAR-UPPER-CASE? CHAR)
(CHAR-LOWER-CASE? CHAR)
These predicates should be true only of upper and lower case
alphabetic characters, respectively. CHAR must be a character.
(CHAR-UPCASE CHAR)
(CHAR-DOWNCASE CHAR)
These operations convert alphabetic characters to upper and lower
case, respectively. If CHAR is not alphabetic, it is returned. CHAR
must be a character.
Character-sets
A character-set is an abstract object that represents a (mathematical)
set of characters. Character-set searches are most useful for parsing
strings. The required operations on character-sets are:
(CHAR-SET-MEMBER? CHAR-SET CHAR)
A predicate which is true iff the character CHAR is a member of the
character-set CHAR-SET.
!
----------------------------------------------------------------------
Basic String Operations
These are the most primitive of the string operations. All other
string operations can be constructed from these.
(STRING-ALLOCATE LENGTH)
This operation allocates a new string, of the given LENGTH, and
returns it. The contents of the string are unspecified. LENGTH must
be a non-negative integer.
(STRING? OBJECT)
This is a boolean operation which is true of all strings.
(STRING-LENGTH STRING)
This operation returns the length of STRING, which must be a string.
The value is a non-negative integer.
(STRING-REF STRING INDEX)
This operation returns the INDEX'th element of STRING, a character.
STRING must be a string, and INDEX must be a valid index of STRING.
(STRING-SET! STRING INDEX CHAR)
This operation stores the character CHAR as the INDEX'th element of
STRING. STRING must be a string, INDEX must be a valid index of
STRING, and CHAR must be a character.
!
----------------------------------------------------------------------
Standard Operations
These operations are useful enough to deserve being "standard" in most
implementations.
(MAKE-STRING LENGTH CHAR)
This allocates a new string of the given LENGTH, and initializes all
of its elements to CHAR. LENGTH must be a non-negative integer, and
CHAR must be a character.
(STRING-FILL! STRING CHAR)
This fills the string STRING with the character CHAR.
(STRING-NULL? STRING)
This predicate is true only of strings whose length is zero. STRING
must be a string.
(SUBSTRING STRING START END)
This operation returns a new string, which is the substring designated
by <STRING, START, END>; this must be a valid substring designator.
(STRING-APPEND STRING1 STRING2)
This operation returns a new string, which is the concatenation of
STRING1 followed by STRING2, both of which must be strings. This
operation may (optionally) be n-ary, for n greater than 0.
(STRING-COPY STRING)
This operation returns a new copy of STRING, which must be a string.
(STRING->LIST STRING)
(LIST->STRING CHARS)
These operations convert between strings and lists of characters.
STRING must be a string, and CHARS must be a list of characters. The
result of either operation is a newly-created object of the
appropriate form.
!
----------------------------------------------------------------------
Motion Primitives
These operations are useful because they can be used to construct many
other string operations, e.g. SUBSTRING and STRING-APPEND. If strings
are implemented in the usual way on conventional machines, these
operations are extremely simple to implement. It is also possible to
in-line code them in some cases.
(SUBSTRING-FILL! STRING START END CHAR)
This fills the substring <STRING, START, END> with the character CHAR.
(SUBSTRING-MOVE-RIGHT! STRING1 START1 END1 STRING2 START2)
(SUBSTRING-MOVE-LEFT! STRING1 START1 END1 STRING2 START2)
These operations destructively copy the substring <STRING1, START1,
END1> to the string STRING2 starting at the index START2. It must be
the case that <STRING2, START2, (+ START2 (- END1 START1))> is a
substring; this latter substring is destructively modified to contain
the contents of the former substring.
The operations differ only when the two substrings overlap, i.e. when
STRING1 and STRING2 are EQ? and the index sets of the substrings are
not disjoint. In this case, the operations are defined to copy the
elements of the first substring serially. SUBSTRING-MOVE-RIGHT!
copies the first substring from left to right, while
SUBSTRING-MOVE-LEFT! copies from right to left. Thus, for example,
the two operations can be used to shift groups of characters right or
left, respectively, within a given string.
!
----------------------------------------------------------------------
Comparison Primitives
Each group of comparisons contains these operations:
1. Compare two substrings, case sensitive.
2. Compare two strings, case sensitive.
3. Compare two substrings, case insensitive.
4. Compare two strings, case insensitive.
The groups are described as a unit since they are essentially very
similar. In all cases the arguments must be valid substrings or
strings.
(SUBSTRING-EQUAL? STRING1 START1 END1 STRING2 START2 END2)
(STRING-EQUAL? STRING1 STRING2)
(SUBSTRING-EQUAL-CI? STRING1 START1 END1 STRING2 START2 END2)
(STRING-EQUAL-CI? STRING1 STRING2)
These are boolean equality predicates, which are true only when the
two (sub)strings are the same length and contain the same characters.
(SUBSTRING-LESS? STRING1 START1 END1 STRING2 START2 END2)
(STRING-LESS? STRING1 STRING2)
(SUBSTRING-LESS-CI? STRING1 START1 END1 STRING2 START2 END2)
(STRING-LESS-CI? STRING1 STRING2)
These are boolean order predicates, which compare the (sub)strings
using the standard dictionary order; i.e. the leftmost unequal
characters determine the order, or if no such character exists, the
shorter (sub)string is less. The character ordering is determined by
the character operations CHAR-LESS? and CHAR-LESS-CI?.
(SUBSTRING-MATCH-FORWARD STRING1 START1 END1 STRING2 START2 END2)
(STRING-MATCH-FORWARD STRING1 STRING2)
(SUBSTRING-MATCH-FORWARD-CI STRING1 START1 END1 STRING2 START2 END2)
(STRING-MATCH-FORWARD-CI STRING1 STRING2)
These operations compare the (sub)strings from left to right,
returning the number of characters that were the same.
(SUBSTRING-MATCH-BACKWARD STRING1 START1 END1 STRING2 START2 END2)
(STRING-MATCH-BACKWARD STRING1 STRING2)
(SUBSTRING-MATCH-BACKWARD-CI STRING1 START1 END1 STRING2 START2 END2)
(STRING-MATCH-BACKWARD-CI STRING1 STRING2)
These operations compare the (sub)strings from right to left,
returning the number of characters that were the same.
!
----------------------------------------------------------------------
Character Search Primitives
Each group of searches contains these operations:
1. Search substring for character, case sensitive.
2. Search string for character, case sensitive.
3. Search substring for character, case insensitive.
4. Search string for character, case insensitive.
5. Search substring for character in set.
6. Search string for character in set.
In all cases the arguments must be valid substrings, strings,
characters, or character-sets, as appropriate.
(SUBSTRING-FIND-NEXT-CHAR STRING START END CHAR)
(STRING-FIND-NEXT-CHAR STRING CHAR)
(SUBSTRING-FIND-NEXT-CHAR-CI STRING START END CHAR)
(STRING-FIND-NEXT-CHAR-CI STRING CHAR)
(SUBSTRING-FIND-NEXT-CHAR-IN-SET STRING START END CHAR-SET)
(STRING-FIND-NEXT-CHAR-IN-SET STRING CHAR-SET)
These operations return the index of the leftmost occurrence of the
character CHAR (or character-set CHAR-SET) within the given
(sub)string, or #!FALSE if there is no occurrence.
(SUBSTRING-FIND-PREVIOUS-CHAR STRING START END CHAR)
(STRING-FIND-PREVIOUS-CHAR STRING CHAR)
(SUBSTRING-FIND-PREVIOUS-CHAR-CI STRING START END CHAR)
(STRING-FIND-PREVIOUS-CHAR-CI STRING CHAR)
(SUBSTRING-FIND-PREVIOUS-CHAR-IN-SET STRING START END CHAR-SET)
(STRING-FIND-PREVIOUS-CHAR-IN-SET STRING CHAR-SET)
These operations return the index of the rightmost occurrence of the
character CHAR (or character-set CHAR-SET) within the given
(sub)string, or #!FALSE if there is no occurrence.
!
----------------------------------------------------------------------
Case
Each of the following groups contains the following operations:
1. A predicate to determine a substring's case.
2. A predicate to determine a string's case.
3. A operation to destructively set a substring's case.
4. A operation to destructively set a string's case.
The meanings of the operations should be clear from their names.
(SUBSTRING-UPPER-CASE? STRING START END)
(STRING-UPPER-CASE? STRING)
(SUBSTRING-UPCASE! STRING START END)
(STRING-UPCASE! STRING)
(SUBSTRING-LOWER-CASE? STRING START END)
(STRING-LOWER-CASE? STRING)
(SUBSTRING-DOWNCASE! STRING START END)
(STRING-DOWNCASE! STRING)
(SUBSTRING-CAPITALIZED? STRING START END)
(STRING-CAPITALIZED? STRING)
(SUBSTRING-CAPITALIZE! STRING START END)
(STRING-CAPITALIZE! STRING)
The (sub)string in the ...CAPITALIZE... operations may not be null.
!
----------------------------------------------------------------------
Appendix: An Implementation
The following is an examplary implementation of the above string
operations (in terms of the basic operations). This implementation is
intended to supplement the preceding specification by providing an
explicit formal description of the semantics of the operations.
There is no error checking in this code, since it was felt that it
would obscure the form somewhat.
!
;;;; Standard Operations
(define (make-string length char)
(let ((result (string-allocate length)))
(substring-fill! result 0 length char)
result))
(define (string-fill! string char)
(substring-fill! string 0 (string-length string) char))
(define (string-null? string)
(zero? (string-length string)))
(define (substring string start end)
(let ((result (string-allocate (- end start))))
(substring-move-right! string start end result 0)
result))
(define (string-append string1 string2)
(let ((length1 (string-length string1))
(length2 (string-length string2)))
(let ((result (string-allocate (+ length1 length2))))
(substring-move-right! string1 0 length1 result 0)
(substring-move-right! string2 0 length2 result length1)
result)))
(define (string-copy string)
(let ((length (string-length string)))
(let ((result (string-allocate length)))
(substring-move-right! string 0 length result 0)
result)))
(define (string->list string)
(let ((end (string-length string)))
(define (loop index)
(if (= index end)
'()
(cons (string-ref string index)
(loop (1+ index)))))
(loop 0)))
(define (list->string chars)
(let ((result (string-allocate (length chars))))
(define (loop index chars)
(if (null? chars)
result
(begin (string-set! result index (car chars))
(loop (1+ index) (cdr chars)))))
(loop 0 chars)))
!
;;;; Motion Primitives
(define (substring-fill! string start end char)
(define (loop index)
(if (not (= index end))
(begin (string-set! string index char)
(loop (1+ index)))))
(loop start))
(define (substring-move-right! string1 start1 end1 string2 start2)
(define (loop index1 index2)
(if (not (= index1 end1))
(begin (string-set! string2 index2 (string-ref string1 index1))
(loop (1+ index1) (1+ index2)))))
(loop start1 start2))
(define (substring-move-left! string1 start1 end1 string2 start2)
(define (loop index1 index2)
(if (not (= index1 start1))
(begin (string-set! string2
(-1+ index2)
(string-ref string1 (-1+ index1)))
(loop (-1+ index1) (-1+ index2)))))
(loop end1 end2))
!
;;;; Comparison Primitives
(define substring-equal?)
(define substring-equal-ci?)
(let ()
(define (make-substring-equal? char-equal?)
(lambda (string1 start1 end1 string2 start2 end2)
(define (loop index1 index2)
(or (= index1 end1)
(and (char-equal? (string-ref string1 index1)
(string-ref string2 index2))
(loop (1+ index1) (1+ index2)))))
(and (= (- end1 start1) (- end2 start2))
(loop start1 start2))))
(set! substring-equal?
(make-substring-equal? char-equal?))
(set! substring-equal-ci?
(make-substring-equal? char-equal-ci?)))
(define substring-less?)
(define substring-less-ci?)
(let ()
(define (make-substring-less? char-equal? char-less?)
(lambda (string1 start1 end1 string2 start2 end2)
(define (loop index1 index2)
(cond ((or (= index1 end1)
(= index2 end2))
(< (- end1 start1)
(- end2 start2)))
((char-equal? (string-ref string1 index1)
(string-ref string2 index2))
(loop (1+ index1) (1+ index2)))
(else
(char-less? (string-ref string1 index1)
(string-ref string2 index2)))))
(loop start1 start2)))
(set! substring-less?
(make-substring-less? char-equal? char-less?))
(set! substring-less-ci?
(make-substring-less? char-equal-ci? char-less-ci?)))
(define substring-match-forward)
(define substring-match-forward-ci)
(let ()
(define (make-substring-match-forward char-equal?)
(lambda (string1 start1 end1 string2 start2 end2)
(define (loop index1 index2 n)
(if (or (= index1 end1)
(= index2 end2)
(not (char-equal? (string-ref string1 index1)
(string-ref string2 index2))))
n
(loop (1+ index2) (1+ index2) (1+ n))))
(loop start1 start2 0)))
(set! substring-match-forward
(make-substring-match-forward char-equal?))
(set! substring-match-forward-ci
(make-substring-match-forward char-equal-ci?)))
!
(define substring-match-backward)
(define substring-match-backward-ci)
(let ()
(define (make-substring-match-backward char-equal?)
(lambda (string1 start1 end1 string2 start2 end2)
(define (loop index1 index2 n)
(if (or (= index1 start1)
(= index2 start2)
(not (char-equal? (string-ref string1 (-1+ index1))
(string-ref string2 (-1+ index2)))))
n
(loop (-1+ index2) (-1+ index2) (1+ n))))
(loop end1 end2 0)))
(set! substring-match-backward
(make-substring-match-backward char-equal?))
(set! substring-match-backward-ci
(make-substring-match-backward char-equal-ci?)))
(define string-equal?)
(define string-equal-ci?)
(define string-less?)
(define string-less-ci?)
(define string-match-forward)
(define string-match-forward-ci)
(define string-match-backward)
(define string-match-backward-ci)
(let ()
(define (string-comparison substring-comparison)
(lambda (string1 string2)
(substring-comparison string1 0 (string-length string1)
string2 0 (string-length string2))))
(set! string-equal?
(string-comparison substring-equal?))
(set! string-equal-ci?
(string-comparison substring-equal-ci?))
(set! string-less?
(string-comparison substring-less?))
(set! string-less-ci?
(string-comparison substring-less-ci?))
(set! string-match-forward
(string-comparison substring-match-forward))
(set! string-match-forward-ci
(string-comparison substring-match-forward-ci))
(set! string-match-backward
(string-comparison substring-match-backward))
(set! string-match-backward-ci
(string-comparison substring-match-backward-ci)))
!
;;;; Character Search Primitives
(define substring-find-next-char)
(define substring-find-next-char-ci)
(define substring-find-next-char-in-set)
(let ()
(define (find-next char-test)
(lambda (string start end key)
(define (loop index)
(and (not (= index end))
(if (char-test key (string-ref string index))
index
(loop (1+ index)))))
(loop start)))
(set! substring-find-next-char (find-next char-equal?))
(set! substring-find-next-char-ci (find-next char-equal-ci?))
(set! substring-find-next-char-in-set (find-next char-set-member?)))
(define substring-find-previous-char)
(define substring-find-previous-char-ci)
(define substring-find-previous-char-in-set)
(let ()
(define (find-previous char-test)
(lambda (string start end key)
(define (loop index)
(and (not (= index start))
(let ((index (-1+ index)))
(if (char-test key (string-ref string index))
index
(loop index)))))
(loop end)))
(set! substring-find-previous-char (find-previous char-equal?))
(set! substring-find-previous-char-ci (find-previous char-equal-ci?))
(set! substring-find-previous-char-in-set (find-previous char-set-member?)))
(define string-find-next-char)
(define string-find-next-char-ci)
(define string-find-next-char-in-set)
(define string-find-previous-char)
(define string-find-previous-char-ci)
(define string-find-previous-char-in-set)
(let ()
(define (string-search substring-search)
(lambda (string char)
(substring-search string 0 (string-length string) char)))
(set! string-find-next-char
(string-search substring-find-next-char))
(set! string-find-next-char-ci
(string-search substring-find-next-char-ci))
(set! string-find-next-char-in-set
(string-search substring-find-next-char-in-set))
(set! string-find-previous-char
(string-search substring-find-previous-char))
(set! string-find-previous-char-ci
(string-search substring-find-previous-char-ci))
(set! string-find-previous-char-in-set
(string-search substring-find-previous-char-in-set)))
!
;;;; Case
(define substring-upper-case?)
(define substring-lower-case?)
(let ()
(define (substring-has-case? char-has-case?)
(lambda (string start end)
(define (loop index)
(or (= index end)
(and (char-has-case? (string-ref string index))
(loop (1+ index)))))
(loop start)))
(set! substring-upper-case?
(substring-has-case? char-upper-case?))
(set! substring-lower-case?
(substring-has-case? char-lower-case?)))
(define substring-upcase!)
(define substring-downcase!)
(let ()
(define (substring-set-case! char-set-case)
(lambda (string start end)
(define (loop index)
(if (not (= index end))
(begin (string-set! string
index
(char-set-case (string-ref string index)))
(loop (1+ index)))))
(loop start)))
(set! substring-upcase!
(substring-set-case! char-upcase))
(set! substring-downcase!
(substring-set-case! char-downcase)))
(define (substring-capitalized? string start end)
(define (loop end)
(or (= end end)
(and (char-lower-case? (string-ref string end))
(loop (1+ end)))))
(and (not (= start end))
(char-upper-case? (string-8b-ref string 0))
(loop (1+ start))))
(define (substring-capitalize! string start end)
(substring-upcase! string start (1+ start))
(substring-downcase! string (1+ start) end))
(define string-upper-case?)
(define string-lower-case?)
(define string-upcase!)
(define string-downcase!)
(define string-capitalized?)
(define string-capitalize!)
(let ()
(define (string-op substring-op)
(lambda (string)
(substring-op string 0 (string-length string))))
(set! string-upper-case?
(string-op substring-upper-case?))
(set! string-lower-case?
(string-op substring-lower-case?))
(set! string-upcase!
(string-op substring-upcase!))
(set! string-downcase!
(string-op substring-downcase!))
(set! string-capitalized?
(string-op substring-capitalized?))
(set! string-capitalize!
(string-op substring-capitalize!)))
∂14-Jan-85 0217 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Re: policy to adopt
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 14 Jan 85 02:16:54 PST
Received: from unc by csnet-relay.csnet id a000234; 14 Jan 85 5:09 EST
Received: by unc (4.12/4.7) id AA00749; Sun, 13 Jan 85 22:21:36 est
Date: Sun, 13 Jan 85 22:21:36 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8501140321.AA00749@unc>
To: KMP@mit-mc.ARPA, SCHEME@mit-mc.ARPA
Subject: Re: policy to adopt
I have certainly gotten the impression that everyone WAS after
a Common Scheme of sorts, and not just so that papers use common
syntax. Why standardize on so many of the function names? More
importantly, why standardize on the controversial nil/t/boolean
issue? Why have numbers and streams subcommittees?
I think we need more discussion of the details of the proposal
rather than less. Standardizing is dangerous if done only half-
heartedly. We must be absolutely sure of what we standardize on,
since we will likely be stuck with our decisions for several
years.
As for the list-length, list-append issue, I think we ought to take
one of two stances:
Stance 1: sequence-type functions such as ref, length and
append should be prefixed by "list-" for the
list version, "string-" for the string version,
and "vector-" for the vector version.
Stance 2: sequence-type functions such as ref, length and
append should be prefixed by nothing for the
list version, "string-" for the string version,
and "vector-" for the vector version.
The first stance is preferable because of the symmetry, the second
because the names for the list versions (probably the most commonly
used) are shorter. I think that the first stance is less confusing
and less likely to cause trouble.
Cheers,
Kent Dybvig
∂15-Jan-85 1914 @MIT-MC:BARTLEY%ti-csl.csnet@csnet-relay.arpa Re: Scheme String Operations: the Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 15 Jan 85 19:14:04 PST
Received: from ti-csl by csnet-relay.csnet id ab07537; 15 Jan 85 22:01 EST
Date: 15 Jan 1985 1445-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: Re: Scheme String Operations: the Report
To: CPH%MIT-OZ@mit-mc.ARPA, Bartley%ti-csl.csnet@csnet-relay.arpa,
Jensen%ti-csl.csnet@csnet-relay.arpa, Oxley%ti-csl.csnet@csnet-relay.arpa,
Scheme@mit-mc.ARPA
cc: Bartley%ti-csl.csnet@csnet-relay.arpa
In-Reply-To: Your message of 14-Jan-85 0529-CST
Received: from csl60 by ti-csl; Tue, 15 Jan 85 20:45 CST
Chris,
Thanks for mailing out the preliminary report on your proposal for string
operations for Scheme. Here are my initial reactions.
-- You were clearly influenced by Common LISP (CL), since at least 27 of
your functions have direct analogues in CL. You rarely use the same name
as CL uses, however. I tend to agree with most of your name choices, with
one exception: CL uses the suffixes =, <, etc. for case sensitive
comparisons of characters and strings and the suffixes EQUAL, LESSP, etc
for case-insensitive comparisons. I prefer to adopt that convention rather
than inventing the suffix -CI.
We should definitely preserve our conventions regarding suffixed ? and !
characters. Thus, CL's CHAR-LESSP and NSTRING-UPCASE should be renamed
CHAR-LESS? and STRING-UPCASE! for Scheme.
-- We probably need a (CHAR? obj) predicate. The following are useful;
can we agree on their meaning?
(CHAR->INTEGER char) ; CL's CHAR-CODE ?
(INTEGER->CHAR n) ; CL's CODE-CHAR ?
-- The order of arguments to CHAR-SET-MEMBER? is reversed from that of
MEMBER, MEMV, and MEMQ.
-- How is a CHAR-SET represented? Created? Modified?
-- Why distinguish STRING-ALLOCATE from MAKE-STRING? By analogy with
MAKE-VECTOR, shouldn't MAKE-STRING take the second argument optionally?
-- May I assume that string and character values are printed (and read)
as defined by CL?
-- May I assume that all of the operations you defined are procedures,
not special forms?
-- May I assume that SUBSTRING and other names written without ! always
return a copy rather than sharing structure?
-- One way to reduce the number of operations is to combine the STRING-
and SUBSTRING- operations by accepting optional substring operands. For
example, specify only
(STRING-FILL! string char { start { end }} )
instead of
(STRING-FILL! string char) and
and (SUBSTRING-FILL! string start end char)
Note that the <char> argument has been repositioned.
It would be useful to let either <start> or <end> default. In the example
above, we could interpret
(STRING-FILL! string char start)
as filling from <start> to the end of the string.
-- What should happen when indexes cross (start>end) or go outside the
proper range?
-- Are you suggesting that the Basic Character Operations, Basic String
Operations, and Standard Operations be 'required' and the rest be
'optional'? If not, where would you draw the line? Do you use all of
these operations yourself?
-- Is the character datatype in MIT Scheme extended the same way CL has
gone? Do you support font and/or bit info? Have you added operations to
MIT Scheme beyond those you've proposed in your report?
-- In summary, the proposal looks sound and I have no arguments with the
functionality you are proposing. I'll pass on further comments after we've
had time to digest it more thoroughly.
Regards,
David Bartley
-------
∂15-Jan-85 2339 @MIT-MC:CPH@MIT-OZ Scheme String Operations: the Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 15 Jan 85 23:38:57 PST
Date: Wed, 16 Jan 1985 02:40 EST
Message-ID: <CPH.12079941473.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: David Bartley <Bartley%ti-csl.csnet@CSNET-RELAY.ARPA>
Cc: Jensen%ti-csl.csnet@CSNET-RELAY.ARPA,
Oxley%ti-csl.csnet@CSNET-RELAY.ARPA, Scheme@MIT-MC.ARPA
Subject: Scheme String Operations: the Report
In-reply-to: Msg of 15 Jan 1985 15:45-EST from David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
Date: Tuesday, 15 January 1985 15:45-EST
From: David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
-- We probably need a (CHAR? obj) predicate. The following are useful;
can we agree on their meaning?
(CHAR->INTEGER char) ; CL's CHAR-CODE ?
(INTEGER->CHAR n) ; CL's CODE-CHAR ?
-- How is a CHAR-SET represented? Created? Modified?
-- Is the character datatype in MIT Scheme extended the same way CL has
gone? Do you support font and/or bit info? Have you added operations to
MIT Scheme beyond those you've proposed in your report?
In answer to all of these: I purposefully limited my description of
characters (and character sets) to that minimum required to describe
the string abstraction. I did this because I felt that the string
abstraction was very largely independent of the character abstraction;
this method shows the dependence pretty clearly.
Further, I recall that we agreed to do characters "the CL way" at the
workshop, at least so far as syntax. My character datatype is heavily
influenced by CL, and implements bits but not fonts (I don't need them
now). I would be willing to discuss both this and the character set
abstraction if there is interest.
-- You were clearly influenced by Common LISP (CL)...
Not so! The string operations were mostly designed from scratch; I
was unaware that they were so similar.
...CL uses the suffixes =, <, etc. for case sensitive
comparisons of characters and strings and the suffixes EQUAL, LESSP, etc
for case-insensitive comparisons. I prefer to adopt that convention...
Mumble. I don't particularly like those names, but then, I don't
particularly care about the names anyway. I'm not terribly happy with
the names I chose, either. Whatever folks like is fine with me.
-- May I assume that string and character values are printed (and read)
as defined by CL?
Yes; I think that we agreed upon this at the workshop.
-- May I assume that all of the operations you defined are procedures,
not special forms?
Yes!!! (with feeling)
-- May I assume that SUBSTRING and other names written without ! always
return a copy rather than sharing structure?
Yes. Furthermore, operations written with a "!" return undefined values.
-- Why distinguish STRING-ALLOCATE from MAKE-STRING? By analogy with
MAKE-VECTOR, shouldn't MAKE-STRING take the second argument optionally?
-- One way to reduce the number of operations is to combine the STRING-
and SUBSTRING- operations by accepting optional substring operands.
Gee, I guess that I don't feel too good about that. While it is true
that this cuts down on the number of names, I have an irrational fear
of widespread optionalogy. Perhaps it is from overexposure to
flagrant misuse, but I prefer not to use optionals at the "lower
levels" of my code.
Also, I was particularly thinking about the workshop, and I recall
there was very mixed feeling about optional arguments, rest arguments,
etc... I felt that this would be more acceptable to the community as a
whole.
-- The order of arguments to CHAR-SET-MEMBER? is reversed from that of
MEMBER, MEMV, and MEMQ.
Hmm... This was chosen to match other stuff... in particular,
VECTOR-REF, LIST-REF, etc. The convention is: the compound structure
first, the key second. In hindsight, it clearly should match MEMfoo.
-- What should happen when indexes cross (start>end) or go outside the
proper range?
Sorry, I should have spelled that out. It will signal an error, in
all cases (although maybe not at the most reasonable place, in my
implementation). I specific: everywhere where I have described the
arguments as "a string", "a character", "a substring", etc., those can
be construed as requirements. Errors will happen if those things are
not true.
-- Are you suggesting that the Basic Character Operations, Basic String
Operations, and Standard Operations be 'required' and the rest be
'optional'? If not, where would you draw the line? Do you use all of
these operations yourself?
No, I was making no such suggestion; I would be hesitant to do so
without some discussion. I do feel that the 'Basic String Operations'
and 'Standard Operations', with the exception of STRING-ALLOCATE,
STRING-SET!, and STRING-FILL!, are very useful, and perhaps should be
required. But then we have already agreed upon those in the 'Basic'
category, and I think that there would be little disagreement about
the 'Standard' ones.
But I can't really say where one should draw the line; all of these
procedures are useful if one ever does anything even moderately hairy.
Personally, I have used most of these operations pretty freely in the
editor.
I have found, though, that a particular pattern has emerged. The
mutating operations are used (in conjunction with STRING-ALLOCATE)
almost exclusively for the construction of higher level, non-mutating
operations like SUBSTRING and STRING-APPEND. I think that such things
might safely be relegated to the realm of 'system programming', for
those who prefer to make such a distinction.
Anyway, if there is interest in working out the boundaries of
'required' vs. 'optional' here, I am perfectly willing to add more of
my flame to the conflagration.
∂24-Jan-85 1227 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa Purpose of a "common" Scheme
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 24 Jan 85 12:00:43 PST
Received: from indiana by csnet-relay.csnet id aa09096; 24 Jan 85 14:38 EST
Date: Thu, 24 Jan 85 13:27:13 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA11826; Thu, 24 Jan 85 13:27:13 est
To: scheme@mit-mc.ARPA
Subject: Purpose of a "common" Scheme
Surely different people have different purposes in wanting a more
standardized Scheme. Half the fun is getting everyone to work
together and to agree. It helps to be vague about the purposes.
Here's my view, from a draft introduction to the final report on
the workshop:
Scheme shares with Common Lisp [\ref] the goal of a core
language common to several implementations. Scheme differs
from Common Lisp in that the purpose of the common language
has more to do with porting ideas than with porting code.
It is appropriate therefore that Scheme is much smaller, is
less pervasively specified, and will evolve faster than
Common Lisp.
Let me know by direct mail if you object to that wording.
William Clinger (willc@indiana)
∂31-Jan-85 0921 @MIT-MC:mw%brandeis.csnet@csnet-relay.arpa Resources for Scheme course
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 31 Jan 85 09:17:38 PST
Received: from brandeis by csnet-relay.csnet id a002562; 31 Jan 85 12:13 EST
Received: by brandeis.ARPA (4.12/4.7)
id AA14346; Thu, 31 Jan 85 10:14:16 est
Date: 31 Jan 1985 09:53-EST
From: mw%brandeis.csnet@csnet-relay.arpa
In-Real-Life: Mitchell Wand,faculty
Subject: Resources for Scheme course
To: scheme@mit-mc.ARPA, cth%indiana.csnet@csnet-relay.arpa
Cc: jc%brandeis.csnet@csnet-relay.arpa
Message-Id: <476031183/mw@brandeis>
Brandeis is currently considering creating a laboratory facility for a
course on the style of the Abelson & Sussman book. For this purpose, I
am collecting data on the state of various workstation implementations
of Scheme and related languages (e.g. T). I know about some
implementations, but I'd like to hear about others, and get up-to-date
information even about the ones I've heard of. In particular:
1) What workstations would you recommend for such an undertaking, and
what is the availability of appropriate software?
2) What ratio of students/workstation would you recommend? To give
some idea of the planned intensity of the course, let's assume that we
plan to cover about half of the material in A&S in a semester.
3) How many square feet per workstation should we plan on? What other
things in the physical arrangment of the facility should we watch out
for?
Reply to mw@brandeis on csnet. I will post a summary of replies to
the mailing list if interest warrants. Thanks for your help.
-- Mitch Wand
∂01-Feb-85 0930 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa quotient, remainder, letrec
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 1 Feb 85 09:30:03 PST
Received: from indiana by csnet-relay.csnet id aa04954; 1 Feb 85 12:23 EST
Date: Fri, 1 Feb 85 11:13:53 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA02926; Fri, 1 Feb 85 11:13:53 est
To: scheme@mit-mc.ARPA
Subject: quotient, remainder, letrec
In the preliminary report on the Brandeis workshop, I said that quotient and
remainder were such that if x, y, q, and r are integers such that x = qy +
r, y is nonzero, r has the same sign as y and has absolute value less than
that of y, then (quotient x y) was q and (remainder x y) was r. Since that
conflicts with Common Lisp, Franz Lisp, T, Scheme 84, Scheme 312, and maybe
MIT Scheme (my documentation on MIT Scheme isn't clear on the issue), I
retract that definition in favor of:
If x, y, q, and r are integers such that x = qy + r, y is nonzero, r has the
same sign as x, and |r| < |y|, then (quotient x y) is q and
(remainder x y) is r.
The definition of letrec in the preliminary report is wrong.
William Clinger
willc@indiana
∂02-Feb-85 1040 @MIT-MC:BARTLEY%ti-csl.csnet@csnet-relay.arpa Scheme String Operations
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 2 Feb 85 10:39:59 PST
Received: from ti-csl by csnet-relay.csnet id ah03968; 2 Feb 85 10:36 EST
Date: 1 Feb 1985 1453-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: Scheme String Operations
To: Scheme@mit-mc.ARPA, CPH%MIT-OZ@mit-mc.ARPA
cc: SCHEME.Users%ti-csl.csnet@csnet-relay.arpa,
Bartley%ti-csl.csnet@csnet-relay.arpa
Received: from csl60 by ti-csl; Fri, 1 Feb 85 16:57 CST
We at Texas Instruments propose the following revisions to Chris Hanson's
preliminary report on Scheme string operations. Our implementation has
already begun, so we would like to hear objections and other comments as
soon as possible. Thanks!
1. Name changes
For reasonable consistency with Common LISP, we propose the following
name changes:
Preliminary report Our proposal Common LISP
================== ============ ===========
char-equal? char= char=
char-equal-ci? char-equal? char-equal
char-less? char< char<
char-less-ci? char-less? char-lessp
substring-equal? substring=
string-equal? string=
substring-equal-ci? substring-equal?
string-equal-ci? string-equal?
substring-less? substring<
string-less? string<
substring-less-ci? substring-less?
string-less-ci? string-less?
2. Added features
(CHAR? obj) is needed for argument checking, if nothing else.
We agreed at the workshop to include SYMBOL->STRING and STRING->SYMBOL
as essential and STRING->UNINTERNED-SYMBOL as optional.
3. Changes
CHAR-SET-MEMBER should take its arguments in the same order as MEMBER.
4. Essential features
We are not sure how to separate ``essential'' from ``optional''
features, but will probably go with everything labeled ``minimal'' below.
Those labeled ``elective'' will be available but not part of the initial
load of the system.
Basic Character Operations
minimal: CHAR?, CHAR=, CHAR-EQUAL?, CHAR<, CHAR-LESS?,
CHAR-UPCASE, CHAR-DOWNCASE
elective: CHAR-UPPER-CASE?, CHAR-LOWER-CASE?, CHAR-SET-MEMBER?
Basic String Operations
minimal: STRING?, STRING-LENGTH, STRING-REF, STRING-SET!,
STRING->SYMBOL, STRING->UNINTERNED-SYMBOL, SYMBOL->STRING
elective: STRING-ALLOCATE
Standard Operations
minimal: MAKE-STRING, STRING-FILL!, STRING-NULL?, SUBSTRING,
STRING-APPEND, STRING-COPY, STRING->LIST, LIST->STRING
Motion Primitives
minimal: SUBSTRING-FILL!, SUBSTRING-MOVE-RIGHT!, SUBSTRING-MOVE-LEFT!
Comparison Primitives
minimal: SUBSTRING=, STRING=, SUBSTRING-EQUAL?, STRING-EQUAL?,
SUBSTRING<, STRING<, SUBSTRING-LESS?, STRING-LESS?
elective: SUBSTRING-MATCH-FORWARD, STRING-MATCH-FORWARD,
SUBSTRING-MATCH-FORWARD-CI, STRING-MATCH-FORWARD-CI,
SUBSTRING-MATCH-BACKWARD, STRING-MATCH-BACKWARD,
SUBSTRING-MATCH-BACKWARD-CI, STRING-MATCH-BACKWARD-CI
Character Search Primitives
elective: all
Case
elective: all
-- Regards,
David Bartley
-------
∂03-Feb-85 1055 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Re: Scheme String Operations
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 3 Feb 85 10:55:37 PST
Received: from unc by csnet-relay.csnet id aa08903; 3 Feb 85 13:47 EST
Received: by unc (4.12/4.7) id AA06699; Sun, 3 Feb 85 11:59:27 est
Date: Sun, 3 Feb 85 11:59:27 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8502031659.AA06699@unc>
To: scheme@mit-mc.ARPA
Subject: Re: Scheme String Operations
1. I prefer Chris Hanson's names over the Common Lisp or Bartley names.
I find the CL names confusing and nonsensical. Why does "char=" imply
case sensitivity, and "char-equal" insensitivity? The issue is also
confused because CL does not define "equal" to use "char-equal" as is
implied by the naming convention.
I have been using Common Lisp for over a year since helping to bring
Data General's system into existence. Many of us get confused about
which is which. There would be no confusion with a suffix such as
"-ci". Except for possible commercial interests, I can see no benefit
in copying the mistakes of Common Lisp.
2. I would rather spell out the name "character" in all functions rather
than use the shorter "char" but that's probably too much to ask.
3. I wish there weren't so many string functions. I think Chris Hanson
was on the right track with the very primitive set that can be used to
construct all the others. Perhaps we should have that set plus
"string-ref", "string-equal?", "string-less?" "string-equal-ci?",
and "string-less-ci?", "string->list", and "list->string".
4. I have a "string" function in my system that comes in handy --
(string char1 char2 ... charN) => string of char1 ... charN, N >= 0.
For example:
(string #\a #\b #\c) => "abc".
This is easy to write as (lambda x (list->string x)).
It is particularly useful when creating a cursor-addressing string to
send to the tty.
5. I do not view "string->symbol" and "symbol->string" as string functions.
They are symbol creation and destructuring primitives. In fact, I
strongly object to the names since they are not analogous to other
type-conversion functions such as "string->list" and "character->integer".
I'll say more about this in a separate note.
6. As far as optionality is concerned, I would like to see Scheme adopt
an optional argument mechanism. It reduces the namespace and is really
quite easy to implement efficiently. A function like "member" becomes
completely general, allowing not only "eq?", "eqv?" and "equal?" tests
but also any user-defined test. However, until we have optional
arguments that can be defined using a lambda expression, I do not
think we should have primitives with optional arguments. Either the
language has them or it doesn't.
Kent Dybvig
decvax!mcnc!unc!dyb
dyb.unc@Csnet-Relay
∂03-Feb-85 1059 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa string->symbol, symbol->string
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 3 Feb 85 10:57:50 PST
Received: from unc by csnet-relay.csnet id ab08903; 3 Feb 85 13:47 EST
Received: by unc (4.12/4.7) id AA06730; Sun, 3 Feb 85 12:00:27 est
Date: Sun, 3 Feb 85 12:00:27 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8502031700.AA06730@unc>
To: scheme@mit-mc.ARPA
Subject: string->symbol, symbol->string
"symbol->string" and "string->symbol functions are not analogous to
"list->string" or "string->list".
"list->string" converts the same data from one representation into
another, with no loss of information. The same is true for "string->list",
"list->vector", "vector->list" and "character->integer".
A symbol is more than just an alternate representation for a string.
It can be an identifier or keyword. Some implementations allow symbols
to have property lists. All of this information is lost in the conversion
from symbol to string, some is regained in the opposite conversion.
I tend to think of the name of a symbol as an attribute of that symbol.
"symbol->string" is more correctly called "symbol-name".
Furthermore, whereas one can expect "string->list" to return a new list
made up of unique cons-cells, "string->symbol" may return an existing
symbol. The name "intern" is more appropriate for this functionality.
(Perhaps "hash-make-symbol" would be a better name.)
If making a unique, uninterned symbol is supported, the name "make-symbol"
is appropriate.
If what we are really doing when we say "make-symbol" or "string->symbol"
was changing representations, then "string->symbol" would be fine. But
it isn't a type conversion we are doing, it's symbol creation (or lookup).
It seems analogous to saying "make-vector" should be called "integer->vector"
because we are taking an integer, n, and returning a vector of length n.
The name is only one aspect of a symbol in much the same way that the length
is only one aspect of a vector.
Kent Dybvig
decvax!mcnc!unc!dyb
dyb.unc@Csnet-Relay
∂04-Feb-85 0221 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Chez Scheme
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 4 Feb 85 02:21:10 PST
Received: from unc by csnet-relay.csnet id aa11924; 4 Feb 85 5:13 EST
Received: by unc (4.12/4.7) id AA00752; Mon, 4 Feb 85 00:29:49 est
Date: Mon, 4 Feb 85 00:29:49 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8502040529.AA00752@unc>
To: Scheme@mit-mc.ARPA
Subject: Chez Scheme
=> Chez Scheme
Chez Scheme is an implementation of Scheme for Vaxes
running 4.2 Bsd Unix. Chez Scheme supports all required and
most optional features of the anticipated Scheme standard.
The first Chez Scheme release will include an extensive
reference manual. A Chez Scheme tutorial is in preparation
for later releases.
Features of Scheme:
o Clean, concise dialect of Lisp
o Lexically scoped (as is Common Lisp)
o Full function closures (first-class, full funarg)
o Tail-recursion reliably translated into iteration
o Full upward/downward continuations
Features of Chez Scheme:
o Incremental native-code (Vax object code) compiler
o Flexible user interface
o Fast-loading compiled files
o Very fast arbitrary precision integer and rational
arithmetic
o Programmable exception handlers
o Support for multi-tasking (timer interrupts,
continuations)
o String and vector operations
o Macros and structures
o Engines (a process abstraction)
Application programs distributed with the first release
of Chez Scheme include a set operation package, a logic
programming subsystem, a lazy-cons facility, and a generic
matrix, vector and scalar multiplication package.
Faster than many Lisp systems, Chez Scheme may be the
fastest Scheme available. On the Vax 11/780, Chez Scheme is
competitive with benchmarks reported for Franz Lisp and
Digital Common Lisp at last summer's AAAI conference in
Austin, TX. For example, Chez Scheme runs the "Tak"
benchmark in 3.4 cpu seconds and the "Deriv" benchmark in
21.9 cpu seconds. The code tested contained no
declarations, used generic arithmetic, and had no inlined
calls. No separate compilation phase is necessary: all code
loaded into Chez Scheme is compiled incrementally.
Chez Scheme is available for mid-March distribution to
US educational institutions only. We will send a license
agreement to interested parties. There is a $400
distribution fee. We are not yet able to do foreign or
commercial distributions, but contact us if you are
interested.
Write for a copy of the license agreement and ordering
information to:
R. Kent Dybvig
Department of Computer Science
New West Hall (035-A)
University of North Carolina
Chapel Hill, NC 27514
USA
decvax!mcnc!unc!dyb (usenet)
dyb.unc@Csnet-Relay (ARPANET)
∂05-Feb-85 1002 JAR@MIT-MC string->symbol, symbol->string
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 5 Feb 85 10:02:15 PST
Date: 5 February 1985 13:03-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: string->symbol, symbol->string
To: dyb%unc.csnet @ CSNET-RELAY
cc: SCHEME @ MIT-MC
In-reply-to: Msg of Sun 3 Feb 85 12:00:27 est from Kent Dybvig <dyb%unc.csnet at csnet-relay.arpa>
Date: Sun, 3 Feb 85 12:00:27 est
From: Kent Dybvig <dyb%unc.csnet at csnet-relay.arpa>
"symbol->string" and "string->symbol functions are not analogous to
"list->string" or "string->list".
"list->string" converts the same data from one representation into
another, with no loss of information. The same is true for "string->list",
"list->vector", "vector->list" and "character->integer".
There definitely is loss of information in list->vector and friends; you
lose eq-ness and location identity. (vector->list (list->vector l))
gives a copy of the list, so rplacas and rplacds will affect different
cells.
A symbol is more than just an alternate representation for a string.
It can be an identifier or keyword. Some implementations allow symbols
to have property lists. All of this information is lost in the conversion
from symbol to string, some is regained in the opposite conversion.
I tend to think of the name of a symbol as an attribute of that symbol.
"symbol->string" is more correctly called "symbol-name".
How do symbols differ from numbers, which can also be identifiers or
"keywords," in this regard? The way I look at things, all associations
of information with symbols are through tables not intimately tied to
the symbol itself. To say that symbols "have" values is like saying
that integers "have" values - getting a value out of an environment,
given a symbol, is completely analogous to getting a value out of a
vector, given an integer. "Essential scheme" intentionally doesn't have
property lists. Symbol eq-ness is global, so property lists would
violate the desire (based on modularity considerations) to avoid global
state; and given reasonable association tables, they are unnecessary.
Furthermore, whereas one can expect "string->list" to return a new list
made up of unique cons-cells, "string->symbol" may return an existing
symbol. The name "intern" is more appropriate for this functionality.
(Perhaps "hash-make-symbol" would be a better name.)
But character->integer (or char->ascii or whatever you want to call it)
may return an existing integer. What is the difference? Since symbols
are immutable objects, like numbers, it's okay that an existing one is
returned.
Reference to hashing doesn't seem very abstract to me...
If making a unique, uninterned symbol is supported, the name "make-symbol"
is appropriate.
I personally don't believe in uninterned symbols (yet?), but if they
existed then make-symbol would be an okay name, maybe better than
string->uninterned-symbol, but I don't much care.
I think that the "->" convention shouldn't have such a terribly strict
meaning. I guess it's my feeling that string->symbol and symbol->string
are acceptable even if they aren't strictly analogous to list->vector
and vector->list.
Jonathan Rees (JAR@MC)
∂05-Feb-85 1007 JAR@MIT-MC Scheme String Operations
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 5 Feb 85 10:06:52 PST
Date: 5 February 1985 13:08-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: Scheme String Operations
To: SCHEME @ MIT-MC
In-reply-to: Msg of Sun 3 Feb 85 11:59:27 est from Kent Dybvig <dyb%unc.csnet at csnet-relay.arpa>
I should point out that there were people at the workshop who felt
strongly that strings should not be mutable. I don't much care one way
or the other. If the things which use the "..." syntax are immutable
then there ought to be such a thing as vector-of-character; also, if
strings are immutable then it's not clear how they are different from
symbols (maybe just that they self-evaluate). But those of you who
strongly think (or thought) that strings should be immutable should
speak up.
Jonathan
∂21-Feb-85 1259 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa Draft delayed to 15 March
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Feb 85 12:59:45 PST
Received: from indiana by csnet-relay.csnet id ad22218; 21 Feb 85 15:20 EST
Date: Thu, 21 Feb 85 13:14:25 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA04423; Thu, 21 Feb 85 13:14:25 est
To: scheme@mit-mc.ARPA
Subject: Draft delayed to 15 March
The draft of the final report on the Brandeis workshop, which was to have
come out around 1 March, will be delayed to the vicinity of 15 March.
I will be travelling until 4 March and probably won't be able to finish
the draft until I get back. I am sorry for the delay.
William Clinger
Indiana University
∂10-Mar-85 1716 @MIT-MC:GJS@MIT-EECS Numbers Committee Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 10 Mar 85 17:16:24 PST
Received: from MIT-EECS by MIT-MC via Chaosnet; 10 MAR 85 16:53:21 EST
Date: Sun 10 Mar 85 16:53:46-EST
From: GJS%MIT-EECS@MIT-MC.ARPA
Subject: Numbers Committee Report
To: scheme@MIT-MC
Sorry it took so long, but I was afraid to do a half-assed job. The following
report raises 10↑10 issues which should be thought about by all of us. I
believe (after a bit of study) that other language people have been
inadequately careful about the status of numbers in their languages. Numbers
are probably the most complicated data structures we ever deal with, so we must
try to do a good job on them.
The report is entirely the responsibility of GJS (so throw stones at him),
though Bill Rozas, Jon Rees, Guy Steele, Chris Hanson, Hal Abelson, Yekta
Gursel, and Chris Lindblad have made significant contributions -- most of
their stones have been thrown and absorbed (some hurt!).
Scheme Numbers
Intent
Numerical computation has traditionally been neglected by the Lisp
community. Until Common Lisp there has been no carefully thought out
strategy for organizing numerical computation; and with the exception
of the MacLisp system there has been little effort to efficiently
execute numerical code. We applaud the excellent work of the Common
Lisp committee and we accept many of their recommendations. In some
ways we simplify and generalize their proposals in a manner consistent
with the purposes of Scheme.
Scheme numerical operations treat numbers as abstract data, as
independent of the machine representation as is possible. Thus, the
casual user should be able to write simple programs without having to
know that the implementation may use fixed-point, floating-point, and
perhaps other representations for his data. Unfortunately, this
illusion of uniformity can only be sustained approximately -- the
implementation of numbers will leak out of our abstraction whenever
the user must be in control of precision, or accuracy, or when he must
construct especially efficient computations. Thus we also must
provide escape mechanisms so that a sophisticated programmer can
exercise more control of the execution of his code and the
representation of his data when it is essential to do so.
We separate out several apparently related issues of representation --
the abstract numbers, their machine representation, and the
input/output formats of the symbolic expressions which denote
numerical constants. We will use mathematical words such as NUMBER,
COMPLEX, REAL, RATIONAL, and INTEGER for properties of the abstract
numbers, data-structure names such as FIXNUM, BIGNUM, RATNUM, and
FLONUM for machine representations, and names like INT, FIX, FLO, SCI,
RAT, POLAR, and RECT for input/output formats.
Numbers
A Scheme system provides data of type NUMBER, which is the most
general numerical type supported by that system. NUMBER is likely to
be a complicated union type implemented in terms of FIXNUMs, BIGNUMS,
FLONUMS, etc. but this should not be apparent to a naive user. What
the user sees is that the obvious operations on numbers produce the
mathematically expected results, within the limits of the
implementation. Thus if the user divides 3 by 2, he should get
something like 1.5 (or, the exact fraction 3/2). If he adds that
result to itself, and if the implementation can swing it, he should
get an exact 3.
!
Mathematically, numbers may be arranged into a tower of subtypes with
natural projections and injections relating adjacent members of the
tower:
NUMBER
COMPLEX
REAL
RATIONAL
INTEGER
We impose a uniform rule of downward coercion -- a number of one type
is also of a lower type if the injection (up) of the projection (down)
of a number leaves the number unchanged. Since this tower is a real
mathematical entity, Scheme provides predicates and procedures that
access the tower.
Not all Scheme implementations must provide the whole tower, but they
are required to implement a coherent subset, consistent with the
purposes of Scheme.
Exactness
Numbers are either EXACT or INEXACT. A number is exact if it was
derived from EXACT numbers using only EXACT operations. A number is
INEXACT if it models a quantity known only approximately, if it was
derived using INEXACT ingredients, or if it was derived using INEXACT
operations. Thus INEXACTness is a contagious property of a number.
Some operations, such as the square root (of non-square numbers) must
be INEXACT because of the finite precision of our representations.
Other operations are inexact because of implementation requirements.
We emphasize that exactness is independent of the position of the
number on the tower. It is perfectly possible to have an INEXACT
INTEGER or an EXACT REAL; 355/113 may be an EXACT RATIONAL or it may
be an INEXACT RATIONAL approximation to pi, depending on the
application.
Operationally, it is the system's responsibility to combine EXACT
numbers using exact methods, such as infinite precision integer and
rational arithmetic, where possible. An implementation may not be
able to do this (if it does not use infinite precision integers and
rationals), but if a number becomes inexact for implementation reasons
there is probably an important error condition, such as integer
overflow, to be reported. Arithmetic on INEXACT numbers is not so
constrained. The system may use floating point and other flaky
representation strategies for INEXACT numbers. This is not to say
that implementors need not use the best known algorithms for INEXACT
computations -- only that high-quality approximate methods are
allowed. In a system which cannot explicitly distinguish exact from inexact numbers the system must do its best to
maintain precision. Scheme systems must not burden users with
numerical operations described in terms of hardware and
operating-system dependent representations such as FIXNUM and FLONUM.
These representation issues should not be germane to the user's
problems.
!
We highly recommend that the IEEE 32-bit and 64-bit floating-point
standards be adopted for implementations that use floating-point
internal representations. To minimize loss of precision we adopt the
following rules: If an implementation uses several different size
floating-point formats, the results of any operation with a
floating-point result must be expressed in the largest format used to
express any of the floating-point arguments to that operation. It is
desirable (but not required) for potentially irrational operations
such as SQRT, when applied to EXACT arguments, to produce EXACT
answers when that is possible (eg. sqrt[4]=2, exactly). If an EXACT
number (or an INEXACT number represented as a FIXNUM, a BIGNUM, or a
RATNUM) is operated upon so as to produce an INEXACT result (as by
SQRT), then if the result is represented as a FLONUM, then the largest
available format FLONUM must be used; but if the result is expressed
as a RATNUM then the rational approximation must have at least as much
precision as the largest available format FLONUM. (Note that this
last rule is much stronger than that used in Common Lisp. Consider
the result of the square root of a rational, for example.)
Numerical Operations
Scheme provides the usual set of operations for manipulation of
numbers. In the specification below we illustrate each built in
numerical operation with an expression using the default operator
symbol which is bound to that operation in the global environment. In
general, numerical operations require numerical arguments. We use the
following symbols to represent the various types of object in our
descriptions. It is an error for an operation to be presented with an
argument that it is not specified to handle.
obj any arbitrary object
z, z1, ... zi, ... {complex, real, rational, integer} x,
x1, ... xi, ... {real, rational, integer}
q, q1, ... qi, ... {rational, integer} n, n1, ... ni, ...
{integer}
In our descriptions some arguments are required and others are
optionally allowed. For example, numerical comparisons are allowed to
have any number of arguments, but they must have at least two. We
indicate this by putting in explicit argument symbols for each
required argument and a "..." indicating the rest.
!
A. Numerical type predicates can be applied to any kind of argument.
They return true if the object is of the named type. In general, if a
type predicate is true of a number then all higher type predicates are
also true of that number. Not every system supports all of these
types. It is entirely possible to have a Scheme system which only has
INTEGERs, however, it must have all of these predicates.
(NUMBER? obj) (COMPLEX? obj) (REAL? obj) (RATIONAL? obj) (INTEGER?
obj)
B. Numerical predicates test a number for a particular property.
They return a boolean value.
(ZERO? z) (POSITIVE? x) (NEGATIVE? x) (ODD? n) (EVEN? n)
(EXACT? z) (INEXACT? z)
C. Numerical comparisons require all of their arguments to be
numbers. They optionally take many arguments, as in Common Lisp, to
facilitate encoding of range checks. Not all implementations support
this extension. These predicates have redundant names (with and
without the terminal "?") to make all populations happy. Warning: On
INEXACT numbers equality tests will give unreliable results; other
numerical comparisons are only heuristically useful (ask a numerical
analyst about this!)
(= z1 z2 ... zi) all arguments are numerically equal
(=? z1 z2 ... zi)
(< x1 x2 ... xi) arguments are monotonically increasing
(<? x1 x2 ... xi)
(> x1 x2 ... xi) arguments are monotonically decreasing
(>? x1 x2 ... xi)
(<= x1 x2 ... xi) arguments are monotonically nondecreasing
(<=? x1 x2 ... xi)
(>= x1 x2 ... xi) arguments are monotonically nonincreasing
(>=? x1 x2 ... xi)
(max x1 ... xi)
(min x1 ... xi)
!
D. Arithmetic operations require all arguments to be numbers.
Generalization to arbitrary numbers of arguments is implementation
dependent.
(+ z1 ... zi) ==> z1 + ... + zi
(+ z) ==> z
(+) ==> 0 (the identity)
(* z1 ... zi) ==> z1 * ... * zi
(* z) ==> z
(*) ==> 1 (the identity)
(- z1 ... zi) ==> z1 - z2 - ... - zi
(- z) ==> -n
(/ z1 ... zi) ==> z1 / z2 / ... / zi
(/ z) ==> 1/z
(-1+ z) ==> -1 + z
(1+ z) ==> 1 + z
(abs z)
E. Integer division operations are only defined on integers.
(quotient n1 n2) ==> n3
(remainder n1 n2) ==> n4
(modulo n1 n2) ==> n4
In general, these are intended to implement number-theoretic division,
where for positive arguments, n1 and n2
n1 = n3*n2 + n4 and 0 <= n4 < d.
REMAINDER and MODULO differ on negative arguments as in the Common
Lisp REM and MOD procedures -- the remainder always has the sign of
the dividend, the modulo always has the sign of the divisor:
(modulo 13 4) ==> 1 (remainder 13 4) ==> 1
(modulo -13 4) ==> 3 (remainder -13 4) ==> -1
(modulo 13 -4) ==> -3 (remainder 13 -4) ==> 1
(modulo -13 -4) ==> -1 (remainder -13 -4) ==> -1
F. The following procedures are also only defined on integers. The
result is always non-negative.
(gcd n1 ... ni) Greatest common divisor
(gcd) ==> 0 (the identity)
(lcm n1 ... ni) Least common multiple
(lcm) ==> 1 (the identity)
!
G. Integers and rationals can be made using the following procedures.
Note, this does not make the answer EXACT -- in fact, the resulting
number is clearly INEXACT, it can be made EXACT with an exactness
coercion.
(floor x) The largest integer not larger than x
(ceiling x) The smallest integer not smaller than x
(truncate x) The integer of maximal absolute value not larger than x
(round x) The closest integer to n. Rounds to even when halfway.
(rationalize x y) Produces the best rational approximation to x
within the tolerance specified by y.
(rationalize x) Produces the best rational approximation to x,
preserving all of the precision in its
representation.
H. In implementations which support real numbers the following are
defined to conform with the Common Lisp standard as to meaning (be
careful of the branch cuts if complex numbers are allowed).
(exp z) (log z) (expt z1 z2) (sqrt z)
(sin z) (cos z) (tan z) (asin z) (acos z) (atan z1 z2)
I. In implementations which support complex numbers we also provide
(make-rectangular x1 x2) ==> x1 + x2i
(make-polar x3 x4) ==> x3*e↑x4i
(real-part z) (imag-part z) (magnitude z) (angle z)
J. Exactness coercions.
(exact->inexact z) Makes an inexact representation of z.
Pretty harmless.
(inexact->exact z) Makes an exact representation of z.
I hope you know what you are doing here!
K. Type-restricted operations are useful for error checking, or as
advice to a compiler. Scheme optionally supplies such type-restricted
operations: If op is defined on objects of numerical type, t1, and if
t2 is any type lower on the tower than t1, then (t2 op) is the
restricted operator for objects of type t2. For example, the
following are expressions using restricted operators:
((real sqrt) 5) ; Gets the right thing.
((real sqrt) -1) ; Will signal an error.
((integer sqrt) 10) ; Will signal an error -- You probably
wanted to compute (truncate ((real sqrt) 10))
!
For completeness, the system also supplies the most general operations
((number +) 3 4)
The default operations, initially bound to the customary operators in
the global environment, are these most general operations. The
type-restriction procedures REAL, INTEGER, ... are simple maps which
map the default operations to their restricted cousins.
Some systems may want to enhance this facility, to allow integer
subranges or other mathematically meaningful restrictions such as
modular arithmetic, for example:
(((integer-subrange 3 5) +) 2 3 4) ;Will signal an error.
Numerical Input and Output
Scheme allows all of the traditional ways of expressing numerical
constants, though only some may be supported by any particular
implementation. These expressions are intended to be purely
notational; any kind of number may be expressed in any form that the
user deems convenient. Of course, expressing 1/7 as a
limited-precision decimal fraction will not exactly express the
number, but this approximate expression may be just what the user
wants to see.
The expressions of numerical constants can be specified using formats.
The system provides a procedure, NUMBER->STRING, which takes a number
and a format and which produces a string which is the printed
expression of the given number in the given format.
(number->string <number> <format>) ==> <string>
This procedure will mostly be used by sophisticated users and in
system programs. In general, a naive user will need to know nothing
about the formats because the system printer will have reasonable
default formats for all types of NUMBERs. The system reader will
construct reasonable default numerical types for numbers expressed in
each of the formats it recognizes. If a user needs control of the
coercion from strings to numbers he will use STRING->NUMBER, which
takes a string, an exactness, and a radix and which produces a number
of the maximally precise applicable type expressed by the given
string.
(string->number <string> E|I B|O|D|X) ==> <number>
!
Formats may have parameters. For example, the "(SCI 5 2)" format
specifies that a number is to be expressed in FORTRAN scientific
format with 5 significant places and two places after the radix point.
The following are all numerical constant expressions. The comment
shows the format that was used to produce the expression:
123 +123 -123 ; (INT) format
12345678901234567890123456789 ; A big one
355/113 -355/113 +355/113 ; (RAT) format
+123.45 -123.45 ; (FIX 2) format
3.14159265358979 ; (FIX 14) format
3.14159265358979 ; (FLO 15) format
123.450 ; (FLO 6) format
-123.45E-1 ; (SCI 5 2) format
123E3 123E-3 -123E-3 ; (SCI 3 0) format
-1+2i ; (RECT (INT) (INT)) format
1.2@1.570796 ; (POLAR (FIX 1) (FLO 7)) format
A numerical constant may be specified with an explicit radix by a
prefix. The prefixes are: #B (binary), #O (octal), #D (decimal), #X
(hex). A format may specify that a number be expressed in a
particular radix. The radix prefix may be suppressed. For example,
one may express a complex number in polar form with the magnitude in
octal and the angle in decimal as follows:
#o1.2@#d1.570796327 ;(POLAR (FLO 2 (RADIX O)) (FLO (RADIX D))) format
#o1.2@1.570796327 ;(POLAR (FLO 2 (RADIX O)) (FLO (RADIX D S)) format
A numerical constant may be specified to be either EXACT or INEXACT by
a prefix. The prefixes are: #I (inexact), #E (exact). An exactness
prefix may appear before or after any radix prefix that is used. A
format may specify that a number be expressed with an explicit
exactness prefix, or it may force the exactness to be suppressed. For
example, the following are ways to output an inexact value for pi:
#I355/113 ; (RAT (EXACTNESS))
355/113 ; (RAT (EXACTNESS S))
#I3.1416 ; (FIX 4 (EXACTNESS))
An attempt to produce more digits than are available in the internal
machine representation of a number will be marked with a "#" filling
the extra digits. This is not a statement that the implementation
knows or keeps track of the significance of a number, just that the
machine will flag attempts to produce 20 digits of a number which has
only 15 digits of machine representation:
3.14158265358979##### ; (FLO 20 (EXACTNESS S))
In systems with both single and double precision FLONUMs one may want
to specify which size we want to use to internally represent a
constant. For example, we may want a constant whidh is pi rounded to
!
the single precision length, or we might want a long number which has
the value 6/10. In either case, we are specifying an explicit way to
represent an INEXACT number. For this purpose, we allow one to
express a number with a prefix which indicates short or long FLONUM
representation:
#S3.14159265358979 ; Round to short -- 3.141593
#L.6 ; Extend to long -- .600000000000000
Details of formats
The format of a number is notated as a list beginning with a
format descriptor, such as SCI. Following the descriptor are
parameters used by that descriptor, such as the number of significant
digits to be used. Parameters which are omitted are defaulted. Next,
one may specify modifiers, such as RADIX or EXACTNESS, which
themselves may be parameterized. The format descriptors are:
(INT)
Express as an integer. The radix point is implicit. If there are
not enough significant places, as in trying to express 6.0238E23
(internally represented as a 7 digit FLONUM) as an integer we would
get "6023800################".
(RAT n)
Express as a rational fraction. n specifies the largest
denominator to be used in constructing a rational approximation to
the number being expressed. If n is omitted it defaults to
infinity.
(FIX n)
Express with a fixed radix point. n specifies the number of
places to right of the radix point. n defaults to the size of a
single-precision FLONUM. If there are not enough significant
places, as in trying to express 6.0238E23 (internally represented
as a 7 digit FLONUM) as a (FIX 2) we would get
"6023800################.##".
(FLO n)
Express with a floating radix point. n specifies the total number
of places to be displayed. n defaults to the size of a single-
precision FLONUM. If the number is out of range, it is converted
to (SCI). (FLO H) allows the system to heuristically express a FLO
for human consumption (as in MacLisp printer).
!
(SCI n m)
Express in exponential notation. n specifies the total number of
places to be displayed. n defaults to the size of a single-
precision FLONUM. m specifies the number of places to the right of
the radix point. m defaults to n-1. (SCI H) does heuristic
expression.
(RECT r i)
Express as a rectangular form complex number. r and i are formats
for the real and imaginary parts respectively. They default to
(HEUR).
(POLAR m a)
Express as a polar form complex number. m and a are formats for
the magnitude and angle respectively. m and a default to (HEUR).
(HEUR)
Express heuristically, as in the MacLisp printer (see Steele),
using the minimum number of digits required to get an expression
which when coerced back to a number produces the original machine
representation. EXACT numbers are expressed as (INT) or (RAT).
INEXACT numbers are expressed as (FLO H) or (SCI H) depending on
their range. Complex numbers are expressed in (RECT). This is the
normal default of the system printer.
The following modifiers may be added to a numerical format
specification:
(EXACTNESS s)
This controls the expression of the exactness label of a number. s
indicates whether the exactness is to be E (expressed) or S
(suppressed). s defaults to E. If no exactness modifier is
specified for a format the exactness is by default not expressed.
(RADIX r s)
This forces a number to be expressed in the radix r. r may be B
(binary), O (octal), D (decimal), or X (hex). s indicates whether
the radix label is to be E (expressed) or S (suppressed). s
defaults to E. If no radix modifier is specified the default is
decimal and the label is suppressed.
-------
∂11-Mar-85 2110 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 11 Mar 85 21:09:47 PST
Received: from csnet-relay by MIT-MC.ARPA; 11 MAR 85 23:49:17 EST
Received: from indiana by csnet-relay.csnet id ac04021; 11 Mar 85 23:37 EST
Date: Mon, 11 Mar 85 23:20:31 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA14898; Mon, 11 Mar 85 23:20:31 est
To: scheme@mit-mc.ARPA
Subject: I/O proposal
From Gary Brooks and William Clinger at Indiana U:
This is an interim proposal. It takes an old-fashioned view of
streams, and it does nothing about windows and graphics. Arguments to
functions are delimited by angle brackets (<...>) and optional arguments
are further delmited by curly brackets ({...}).
(eof? <object>) Essential
EOF? takes an object and returns true if the object is an end of
file object. The precise set of end of file objects will vary
among implementations, but in any case no end of file object will
ever be a character or an object that can be read in using READ.
Rationale:
A fixed set of end of file objects seems to be simpler than
allowing each input procedure to take yet another optional
argument specifying what to do on end of file. Allowing for a
set of such objects rather than a single such object allows for
different implementation strategies.
(read {<stream>}) Essential
READ takes an input stream as argument and returns the next
object parsable from the stream, updating the stream to point to
the first character past the end of the written representation of
the object. If an end of file is encountered in the input before
any characters are found that can begin an object, then an end of
file object is returned. If an end of file is encountered after
the beginning of an object's written representation, but the
written representation is incomplete and therefore not parsable,
an error must be signalled. The stream argument to READ may be
omitted, in which case it defaults to (CURRENT-INPUT-STREAM).
Rationale:
READ corresponds to Common Lisp's READ-PRESERVING-WHITESPACE.
This will require something like UNREAD-CHAR or PEEK-CHAR
internally. For simplicity, it is never an error to encounter
end of file when READ is called.
(write <object> {<stream>}) Essential
WRITE takes an object and an output stream and writes a
representation of the object to the stream. Strings that appear
in the written representation are enclosed in double quotes, and
within those strings backslash and double quote characters are
escaped by backslashes. (Implementations that allow
slashification within symbols will probably want WRITE to
slashify funny characters in symbols as well.) WRITE returns an
unspecified value. The stream argument to WRITE may be omitted,
in which case it defaults to (CURRENT-OUTPUT-STREAM).
(display <object> {<stream>}) Essential
DISPLAY takes an object and an output stream and writes a
representation of the object to the stream. Strings that appear
in the written representation are not enclosed in double quotes,
and no characters are escaped within those strings. DISPLAY
returns an unspecified value. The stream argument to DISPLAY may
be omitted, in which case it defaults to (CURRENT-OUTPUT-STREAM).
Rationale:
WRITE is for producing machine-readable output, DISPLAY for
producing human-readable output.
(newline {<stream>}) Essential
NEWLINE takes an output stream and writes a newline to the
stream. NEWLINE returns an unspecified value. The stream
argument to NEWLINE may be omitted, in which case it defaults to
(CURRENT-OUTPUT-STREAM).
Rationale:
NEWLINE abstracts away from the implementation details of
ending a line (or is it starting a new one?).
(listen? {<stream>}) Optional
LISTEN? takes an input stream (an interactive stream in the
useful case) and returns true if a character is ready on that
stream so that a READ-CHAR operation will not hang and returns
false if a READ-CHAR operation will hang. If the stream is at
end of file then the value returned by LISTEN? is unspecified.
Rationale:
LISTEN? is needed for interactive input streams.
(read-char {<stream>}) Essential
READ-CHAR takes an input stream and returns the next character
available from the stream, updating the stream to point to the
following character. If no more characters are available from
the stream, an end of file value is returned. The stream
argument to READ-CHAR may be omitted, in which case it defaults
to (CURRENT-INPUT-STREAM).
(display-char <character> {<stream>}) Essential
DISPLAY-CHAR takes a character and an output stream, and writes
the character itself (not a written representation of the
character) to the stream. DISPLAY-CHAR returns an unspecified
value. The stream argument to DISPLAY-CHAR may be omitted, in
which case it defaults to (CURRENT-OUTPUT-STREAM).
Rationale:
READ-CHAR and DISPLAY-CHAR are for low-level I/O.
(load <filename>) Essential
LOAD takes a string that names an existing file containing Scheme
source code. It reads Scheme expressions from the file and
interprets them sequentially as though they had been typed
interactively. It is not specified whether the results of the
expressions are printed. Neither is it specified whether or not the
LOAD procedure affects the values returned by (CURRENT-INPUT-STREAM)
and (CURRENT-OUTPUT-STREAM) during the loading process. LOAD returns
an unspecified value.
Rationale:
For portability LOAD must operate on source files. Its operation
on other kinds of files necessarily varies among implementations.
(transcript-on <file-name>) Optional
TRANSCRIPT-ON takes a string that names an output file to be
created, and returns an unspecified value. The effect of
TRANSCRIPT-ON is to open the named file for output, and to cause
a transcript of subsequent interaction between the user and the
Scheme system to be written to the file. The transcript is ended
by a call to TRANSCRIPT-OFF. Only one transcript may be in
progress at any time. (Some implementations may relax this
restriction.)
(transcript-off) Optional
TRANSCRIPT-OFF takes no arguments and returns an unspecified
value. It ends any transcript in progress and closes the
transcript file.
Rationale:
TRANSCRIPT-ON and TRANSCRIPT-OFF are redundant in some systems,
but systems that need them should provide them.
(stream? <object>) Essential
STREAM? takes one argument and returns true iff its argument is a
stream.
Rationale:
Perhaps STREAM? should be subdivided into INPUT-STREAM? and
OUTPUT-STREAM?.
(current-input-stream) Essential
CURRENT-INPUT-STREAM takes no arguments and returns the current
default input stream.
(current-output-stream) Essential
CURRENT-OUTPUT-STREAM takes no arguments and returns the current
default output stream.
Rationale:
CURRENT-INPUT-STREAM and CURRENT-OUTPUT-STREAM are procedures
rather than variables to allow for various ways to implement the
default streams. Explicit fetching of the default streams is
convenient for programs that want to change the default stream
using WITH-INPUT-FROM-FILE or WITH-OUTPUT-TO-FILE and still use
the original default stream for some I/O; see below.
(call-with-input-file <string> <procedure>) Essential
CALL-WITH-INPUT-FILE takes a procedure of one argument and a
string naming an existing file and calls the procedure with the
stream obtained by opening the named file for input. If the
file cannot be opened, an error should be signalled. If the
procedure returns, then the stream is closed automatically and
the value yielded by the procedure is returned by
CALL-WITH-INPUT-FILE. If the current continuation ever changes in
such a way as to make it doubtful that the procedure will return,
CALL-WITH-INPUT-FILE may close the input stream. The exact
interaction of escape procedures with CALL-WITH-INPUT-FILE is
unspecified.
(call-with-output-file <file-name> <procedure>) Essential
CALL-WITH-OUTPUT-FILE takes a procedure of one argument and a string
naming a file to be created and calls the procedure with the stream
obtained by opening the named file for output. If the file cannot be
be opened, an error should be signalled. If a file with that name
already exists, the effect is unspecified. If the procedure returns,
then the stream is closed automatically and the value yielded by the
procedure is returned by CALL-WITH-OUTPUT-FILE. If the current
continuation ever changes in such a way as to make it doubtful that
the procedure will return, CALL-WITH-OUTPUT-FILE may close the output
stream. The exact interaction of escape procedures with
CALL-WITH-OUTPUT-FILE is unspecified.
Rationale:
CALL-WITH-INPUT-FILE and CALL-WITH-OUTPUT-FILE are convenient for
programs that need to read input from or send output to several
directions at once. They cannot be synthesized from
WITH-INPUT-FROM-FILE and WITH-OUTPUT-TO-FILE so they are the essential
procedures. Whether or not they close files when there is a throw out
of the procedure is mainly a performance issue, of greatest importance
when there is a small limit on the number of files that can be open at
once. If they close files for a throw, then the vagueness of what it
means for the current continuation to change in such a way as to make
it doubtful that a procedure will return, the possibility of a throw
back in, and the vagueness of what it means to close a file, make it
unwise to specify the exact interaction of the file-closing mechanism
with escape procedures.
It is arguable whether the notion of closing a file should be
reflected in the semantics of Scheme. Operating systems require
that files be closed for the following reasons:
1. To reclaim storage. This should be left to the garbage
collector.
2. To prevent some table in the operating system from
overflowing because there are too many files open at once.
Only implementations that have this problem should have to
worry about it.
3. To facilitate file locking. This seems to be the only
semantic reason for closing a file, and even so there are
implementations for which it isn't meaningful.
Because some systems have to worry about closing files, however,
all portable Scheme code must worry about it. We have tried to
follow MIT's lead in isolating the worry within a few standard
procedures.
(open-input-file <file-name>) Optional
OPEN-INPUT-FILE takes a string naming an existing file and
returns an input stream capable of delivering characters from the
file. If the file cannot be opened, an error should be signalled.
(open-output-file <file-name>) Optional
OPEN-OUTPUT-FILE takes a string naming an output file to be
created and returns an output stream capable of writing
characters to a new file by that name. If the file cannot be
opened, an error should be signalled. If a file with the given
name already exists, the effect is unspecified.
(close-input-stream <stream>) Optional
CLOSE-INPUT-STREAM takes an input stream and returns an
unspecified value. If the stream is connected to a file, the
file is closed and the stream rendered incapable of delivering
characters.
(close-output-stream <stream>) Optional
CLOSE-OUTPUT-STREAM takes an output stream and returns an
unspecified value. If the stream is connected to a file, the
file is closed and the stream rendered incapable of writing
characters to it.
Rationale:
OPEN-INPUT-FILE, OPEN-OUTPUT-FILE, CLOSE-INPUT-STREAM, and
CLOSE-OUTPUT-STREAM are needed to use streams whose lifetimes are
not properly nested, which is to say they are seldom needed.
OPEN-INPUT-FILE and OPEN-OUTPUT-FILE are distinct to avoid the
need for a switch argument; if independent switches were
required, it would be better to use switches rather than have a
product space of procedures. CLOSE-INPUT-STREAM and
CLOSE-OUTPUT-STREAM could probably be combined into CLOSE-STREAM
with no great loss. A different set of procedures will
be needed to create streams from and to strings, and the closing
procedures should still work on them. It seems that closing a
string output stream should yield a string, but it isn't clear
what should be returned when a file output stream is closed.
(with-input-from-file <file-name> <thunk>) Optional
WITH-INPUT-FROM-FILE takes a string and a thunk (a procedure of
no arguments). The string must name an existing file. The file
is opened for input, an input stream connected to it is made the
default value returned by (CURRENT-INPUT-STREAM), and the thunk
is invoked. When the thunk returns, (CURRENT-INPUT-STREAM) is
closed and the previous default value returned by
(CURRENT-INPUT-STREAM) is restored. WITH-INPUT-FROM-FILE returns
the value returned by the thunk. Furthermore WITH-INPUT-FROM-FILE
should attempt to close the input stream and restore the default
input stream whenever the current continuation changes in such a
way as to make it doubtful that the thunk will ever return.
(with-output-to-file <file-name> <thunk>) Optional
WITH-OUTPUT-TO-FILE takes a stfung and a thunk. The string names
an output file to be created. The file is opened for output, an
output stream connected to it is made the default value returned
by (CURRENT-OUTPUT-STREAM), and the thunk is invoked. When the
thunk returns, (CURRENT-OUTPUT-STREAM) is closed and the previous
default value returned by (CURRENT-OUTPUT-STREAM) is restored.
WITH-OUTPUT-FROM-FILE returns the value returned by the thunk.
Furthermore WITH-OUTPUT-FROM-FILE should attempt to close the
output stream and restore the default output stream whenever the
current continuation changes in such a way as to make it doubtful
that the thunk will ever return.
It has been suggested that if evaluation of the thunk is
abandoned and later continued then the file should be re-opened
in exactly the same state that it had been in when it was last
closed, but this may be awkward or inefficient in some
implementations.
Rationale:
WITH-INPUT-FROM-FILE and WITH-OUTPUT-TO-FILE are sufficient for
programs that only use one input or one output at a time. Indeed
by nesting them and by fetching the various nested streams using
CURRENT-INPUT-STREAM and CURRENT-OUTPUT-STREAM, arbitrarily many
input or output files may be used. The automatic closing of the
streams may not be terribly important in some implementations,
but the fact that the old defaults are restored is important
semantically. There are several incompatible ways that they
could interact with escape procedures, however, and at this time
it isn't entirely clear which ways are best. See rationale for
CALL-WITH-OUTPUT-FILE and CALL-WITH-INPUT-FILE.
∂12-Mar-85 0940 @MIT-MC:mw%brandeis.csnet@csnet-relay.arpa Re: Numbers Committee Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 12 Mar 85 09:40:41 PST
Received: from csnet-relay by MIT-MC.ARPA; 12 MAR 85 12:39:35 EST
Received: from brandeis by csnet-relay.csnet id ac08006; 12 Mar 85 12:36 EST
Received: by brandeis.ARPA (4.12/4.7)
id AA01743; Tue, 12 Mar 85 11:08:41 est
Date: 12 Mar 1985 10:57-EST
From: mw%brandeis.csnet@csnet-relay.arpa
In-Real-Life: Mitchell Wand,faculty
Subject: Re: Numbers Committee Report
To: scheme@mit-mc.ARPA
Message-Id: <479491071/mw@brandeis>
Three comments (of #I10e10):
1. (/ z1 ... zi) ==> ((z1 / z2) ... / zi)
-- since / is not associative, the order of operation should be
specified explicitly. This is probably just an editing issue.
2. Are formats list structures or some other kind of object? That is
do you write
(let ((format (cons 'FLO '(13))))
(number->string z format))
or is FLO some kind of functional object?
3. In paragraph K, are real, integer, etc supposed to be functions or
keywords? That is, can you write
(let ((range real))
((range sqrt) x)) ?
In either case, this proposal ties up those identifiers in a pretty
complicated way. I am not sure how bad this is, but it deserves
thought.
-- Mitch Wand
∂12-Mar-85 0954 @MIT-MC:mw%brandeis.csnet@csnet-relay.arpa Re: I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 12 Mar 85 09:54:14 PST
Received: from csnet-relay by MIT-MC.ARPA; 12 MAR 85 12:52:56 EST
Received: from brandeis by csnet-relay.csnet id ag08006; 12 Mar 85 12:39 EST
Received: by brandeis.ARPA (4.12/4.7)
id AA02554; Tue, 12 Mar 85 12:08:14 est
Date: 12 Mar 1985 11:22-EST
From: mw%brandeis.csnet@csnet-relay.arpa
In-Real-Life: Mitchell Wand,faculty
Subject: Re: I/O proposal
To: scheme@mit-mc.ARPA
Message-Id: <479492551/mw@brandeis>
A few remarks:
1. LOAD does not specify how it interacts with CURRENT-INPUT-STREAM or
CURRENT-OUTPUT-STREAM while loading. What is to be the preferred way
of loading a bootstrap of the following form:
(define! foo ...)
(define! bar (foo (read)))
..complicated data to be processed by foo during load..
It might be argued that this is bad style, but I am not convinced:
such a bootstrap is less dependent on operating system file naming
conventions than one with the data in a separate file.
2. "A different set of procedures will be needed to create streams from
and to strings, and the closing procedures should still work on them.
It seems that closing a string output stream should yield a string, but
it isn't clear what should be returned when a file output stream is
closed."
I don't understand this at all. The phrase "create streams from and to
strings" is rather difficult to parse, which doesn't help.
3. Are with-input-from-file and with-output-from-file the only way to
change the value of (current-input-stream) and (current-output-stream) ?
If so, shouldn't they be essential ?
-- Mitch Wand
∂12-Mar-85 1306 @MIT-MC:GJS@MIT-OZ Re: Numbers Committee Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 12 Mar 85 13:04:10 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 12 MAR 85 16:03:00 EST
Date: Tue 12 Mar 85 16:02:43-EST
From: Gerald Jay Sussman <GJS%MIT-OZ@MIT-MC.ARPA>
Subject: Re: Numbers Committee Report
To: mw%brandeis.csnet@CSNET-RELAY.ARPA
cc: scheme@mit-mc.ARPA
In-Reply-To: Message from "mw%brandeis.csnet@csnet-relay.arpa" of Tue 12 Mar 85 10:57:00-EST
Three comments (of #I10e10):
***** I certainly hope there are fewer than that!
1. (/ z1 ... zi) ==> ((z1 / z2) ... / zi)
-- since / is not associative, the order of operation should be
specified explicitly. This is probably just an editing issue.
***** I agree and I have already fixed that.
2. Are formats list structures or some other kind of object? That is
do you write
(let ((format (cons 'FLO '(13))))
(number->string z format))
or is FLO some kind of functional object?
***** My initial response is that formats are simple list structures --
there may be some format interpreter, but it should not be part of
Scheme. Presumably this can be later generalized and simplified, if
someone wants to go through the trouble, but I would be happy with
the dumb idea.
3. In paragraph K, are real, integer, etc supposed to be functions or
keywords? That is, can you write
(let ((range real))
((range sqrt) x)) ?
In either case, this proposal ties up those identifiers in a pretty
complicated way. I am not sure how bad this is, but it deserves
thought.
***** The type-restriction operations are intended to be scheme procedures
which take procedures as arguments and which produce procedures as
values. They are bound in the initial environment to the operator
symbols REAL, INTEGER, etc. They may be passed as arguments, etc.
Thus, this does not tie up the identifiers at all, and the example
you give shows that.
-------
∂12-Mar-85 1441 @MIT-MC:CPH@MIT-OZ I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 12 Mar 85 14:41:18 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 12 MAR 85 17:39:56 EST
Date: Tue, 12 Mar 1985 17:25 EST
Message-ID: <CPH.12094520544.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Will Clinger <willc%indiana.csnet@CSNET-RELAY.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: I/O proposal
In-reply-to: Msg of 11 Mar 1985 23:20-EST from Will Clinger <willc%indiana.csnet at csnet-relay.arpa>
The I/O proposal seems quite good! In fact it is nearly identical to
the current MIT Scheme I/O system, which makes me happy.
I wonder why you chose the name "DISPLAY-CHAR" rather than
"WRITE-CHAR"? I prefer "WRITE-CHAR" because it has no connotations of
display terminals, or of being viewed by a human; it says, simply,
that the character was written down somewhere.
Also, I think that you should have both "STREAM?" and its components
"INPUT-STREAM?" and "OUTPUT-STREAM?", because it makes more
information available without really constraining the implementation
in any fundamental way. Clearly bidirectional streams can satisfy
both predicates.
Chris Hanson
∂12-Mar-85 1552 @MIT-MC:GJS@MIT-OZ Re: I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 12 Mar 85 15:52:35 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 12 MAR 85 18:51:29 EST
Date: Tue 12 Mar 85 18:51:01-EST
From: Gerald Jay Sussman <GJS%MIT-OZ@MIT-MC.ARPA>
Subject: Re: I/O proposal
To: willc%indiana.csnet@CSNET-RELAY.ARPA
cc: scheme@mit-mc.ARPA
In-Reply-To: Message from "Will Clinger <willc%indiana.csnet@csnet-relay.arpa>" of Tue 12 Mar 85 00:12:50-EST
I think the I/O proposal is very nice. The only objection I have is the
use of the word STREAM for the IO stuff. My problem is that we used that
word all through chapter 3 of our book to mean the functional programming
idea of (potentially) infinite sequence. It will be very painful to change
that. I propose that the word be changed to one of CHANNEL, PIPE, PORT, TUBE,
or any other appropriate euphemism. I believe that my use of the word STREAM
is consistent with that of other authors on functional programming.
-------
∂14-Mar-85 1024 JAR@MIT-MC interaction of LOAD and CURRENT-INPUT-STREAM
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 14 Mar 85 10:24:15 PST
Date: 14 March 1985 13:23-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: interaction of LOAD and CURRENT-INPUT-STREAM
To: mw%brandeis.csnet @ CSNET-RELAY
cc: SCHEME @ MIT-MC
Date: 12 Mar 1985 11:22-EST
From: mw%brandeis.csnet at csnet-relay.arpa
1. LOAD does not specify how it interacts with CURRENT-INPUT-STREAM or
CURRENT-OUTPUT-STREAM while loading. What is to be the preferred way
of loading a bootstrap of the following form:
(define! foo ...)
(define! bar (foo (read)))
..complicated data to be processed by foo during load..
It might be argued that this is bad style, but I am not convinced:
such a bootstrap is less dependent on operating system file naming
conventions than one with the data in a separate file.
I don't see any reason for LOAD and CURRENT-INPUT-STREAM to interact,
and I think it is much better for them not to. If they don't interact
you have a much better invariants on each, e.g.: doing LOAD on a file is
the same as doing LOAD on a file consisting of the string "(begin "
appended to the file appended to the string ")".
What's wrong with writing
(define! foo ...)
(define! bar (foo '
..complicated data to be processed by foo during load..
)) ?
This way you don't need to do explicit I/O at all.
... And incidentally, I don't remember the rationale for having both
DEFINE! and DEFINE. I understand why DEFINE shouldn't have hairy
syntax, but what does DEFINE! give you that the stripped-down DEFINE
doesn't?
Jonathan
∂14-Mar-85 1228 @MIT-MC:BARTLEY%ti-csl.csnet@csnet-relay.arpa Re: I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 14 Mar 85 12:28:17 PST
Received: from csnet-relay by MIT-MC.ARPA; 14 MAR 85 15:27:14 EST
Received: from ti-csl by csnet-relay.csnet id a021223; 14 Mar 85 14:58 EST
Date: 14 Mar 1985 0952-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: Re: I/O proposal
To: willc%indiana.csnet@csnet-relay.arpa, scheme@mit-mc.ARPA
cc: Bartley%ti-csl.csnet@csnet-relay.arpa
In-Reply-To: Your message of 12-Mar-85 1001-CST
Received: from csl60 by ti-csl; Thu, 14 Mar 85 11:04 CST
Will-- A few questions and remarks about your I/O proposal:
-- What happened to the names PRIN1 and PRINC? Are your WRITE and DISPLAY
meant to be equivalent, respectively, to PRIN1 and PRINC? As I understand
page 382 of the Common LISP (CL) book, your WRITE is not incompatible with
CL's. Likewise, CL doesn't seem to have a DISPLAY. However, I am bothered
by my intuition that DISPLAY should be a terminal-oriented operation.
Bottom line: I vote to go with WRITE and DISPLAY, but the names PRIN1
and PRINC should be reserved as well (as optional aliases). The PRINT
operation should also be optional, with the CL-compatible meaning we agreed
on at the workshop.
-- DISPLAY-CHAR seems to be a redundant, restricted form of DISPLAY. Since
DISPLAY is essential, DISPLAY-CHAR should be dropped.
-- The name LISTEN? also is slightly unintuitive to me; how about INPUT?,
or MORE-INPUT?, or something with "peek" in it.
-- Does READ-CHAR wait for interactive input or return an eof token if
nothing has been buffered up from the keyboard (or comm device, etc)?
-- I oppose the term "stream" and thus the names STREAM?, CURRENT-INPUT-
STREAM, etc., for the reasons Gerry gave. We use "port".
-- With my Pascal (and English) background, I can't help but think of
features named with "with", like WITH-INPUT-FROM-FILE, as syntax, not
procedures. [Did you notice how I began the previous sentence?] I would
prefer a special form: (WITH-INPUT-FROM-FILE <file-name> exp ...). This is
more consistent with CL's macro WITH-INPUT-FROM-STRING. The same goes for
WITH-OUTPUT-FROM-FILE.
-- I don't mind your OPEN- and CLOSE- operations, as long as they remain
optional, but I feel bound to implement OPEN and CLOSE compatibly with CL.
-- I like your approach to eof objects.
-- You have no READ-ATOM. Is there general agreement that READ-ATOM is
unimportant? We have it only by inheritance from Scheme 84.
Regards,
David Bartley
-------
∂15-Mar-85 0801 @MIT-MC:CPH@MIT-OZ I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 15 Mar 85 08:00:52 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 15 MAR 85 10:59:37 EST
Date: Fri, 15 Mar 1985 10:58 EST
Message-ID: <CPH.12095236587.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: David Bartley <Bartley%ti-csl.csnet@CSNET-RELAY.ARPA>
Cc: Scheme@MIT-MC
Subject: I/O proposal
In-reply-to: Msg of 14 Mar 1985 10:52-EST from David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
Date: Thursday, 14 March 1985 10:52-EST
From: David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
-- DISPLAY-CHAR seems to be a redundant, restricted form of DISPLAY. Since
DISPLAY is essential, DISPLAY-CHAR should be dropped.
I don't agree. I think that it is good to have a balanced pair of
procedures for doing character-level I/O.
-- I oppose the term "stream" and thus the names STREAM?, CURRENT-INPUT-
STREAM, etc., for the reasons Gerry gave. We use "port".
Ditto, except that we use "stream" and will cheerfully change it.
-- With my Pascal (and English) background, I can't help but think of
features named with "with", like WITH-INPUT-FROM-FILE, as syntax, not
procedures. [Did you notice how I began the previous sentence?] I would
prefer a special form: (WITH-INPUT-FROM-FILE <file-name> exp ...). This is
more consistent with CL's macro WITH-INPUT-FROM-STRING. The same goes for
WITH-OUTPUT-FROM-FILE.
I disagree -- proliferation of special forms is a communicable disease.
∂16-Mar-85 1017 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Re: I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 16 Mar 85 10:17:40 PST
Received: from csnet-relay by MIT-MC.ARPA; 16 MAR 85 13:16:38 EST
Received: from unc by csnet-relay.csnet id ak00871; 16 Mar 85 13:14 EST
Received: by unc (4.12/4.7) id AA03236; Sat, 16 Mar 85 07:34:57 est
Date: Sat, 16 Mar 85 07:34:57 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8503161234.AA03236@unc>
To: scheme@mit-mc.ARPA
Subject: Re: I/O proposal
I think the overall proposal is quite nice. I do have a couple
of remarks and minor suggestions, though.
1. I would prefer a settable *eof* variable. It is useful sometimes
to specify the value returned on eof. I also think "eof?" is
unnecessarily complex (giving implementors free reign is not
the most important issue here). Besides, if you ask ten people
what they think the function "eof?" does, chances are all ten
will say, "it takes a file as input and returns true iff the
file is at eof." No big deal here, though.
2. I do not think the programmer should be encouraged to change
the default input/output streams. This leads to confusing or
even dangerous behavior when an error or interrupt occurs.
The exception handler normally wants to operate in the same
environment as the interrupted routine, in order that the
user can query the environment (perform stack walkbacks, check
values of variables, etc.). Imagine if the handler prints
a message and queries the user but receives its input from a
disk file because the default input file has been rebound,
e.g. "Really delete *.*? (y/n): ". For this reason, I think
the names should be "default-input-stream" and
"default-output-stream", rather than "current-...". Of course,
"with-input-from-file" and "with-output-to-file" should not be
supported.
I have had experience with this very issue, and troublesome
problems really do occur. I do not want to write every piece of
code to guard against someone changing the default input/output
files on me. I guess we could provide "console-input-stream" and
"console-output-stream" functions, but this seems to complicate
things unnecessarily.
I think it's a good practice anyway to use explicit stream
arguments.
By the way, why are these functions instead of variables?
Isn't this (only perhaps) helping implementrs at the expense
of added complexity?
3. Why have "call-with-input-file" and "call-with-output-file"
rather than an expression-oriented syntax? I think that the
extra level of nesting will be nasty and people will likely
just define syntactic extensions to get rid of it anyway.
(reference my earlier note) I propose:
(with-input-file (<id> <string>) form ...)
and
(with-output-file (<id> <string>) form ...)
with the same semantics. Each set can easily be defined in
terms of the other, but if one is standard it should be the
simplest one to use.
4. I prefer the name "write-char" to "display-char". I take it
the rationale is that "write-char" might imply that it may
be read back in by the function read as a character. I don't
think this is really going to cause confusion; after all, it
may be read back in by read-char, so read-char/write-char is
parallel to to read/write.
..Kent
∂16-Mar-85 1020 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Re: I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 16 Mar 85 10:20:02 PST
Received: from csnet-relay by MIT-MC.ARPA; 16 MAR 85 13:16:44 EST
Received: from unc by csnet-relay.csnet id al00871; 16 Mar 85 13:15 EST
Received: by unc (4.12/4.7) id AA06384; Sat, 16 Mar 85 11:38:25 est
Date: Sat, 16 Mar 85 11:38:25 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8503161638.AA06384@unc>
To: scheme@mit-mc.ARPA
Subject: Re: I/O proposal
I would also like the name "read-char-ready?" instead of "listen?".
∂17-Mar-85 0839 @MIT-MC:JINX@MIT-OZ I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 17 Mar 85 08:38:49 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 17 MAR 85 11:37:49 EST
Date: 17 Mar 1985 11:37 EST (Sun)
Message-ID: <JINX.12095767900.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Kent Dybvig <dyb%unc.csnet@CSNET-RELAY.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: I/O proposal
In-reply-to: Msg of 16 Mar 1985 07:34-EST from Kent Dybvig <dyb%unc.csnet at csnet-relay.arpa>
Just a few comments:
1. Having a way to detect the end of file is needed, beyond that,
both alternatives (eof? or *eof*) can be trivially implemented on top
of the other. I don't feel strongly about either, but I tend to agree
with Kent Dybvig since I view *eof* as more flexible. If the other
option (eof?) is chosen, I would much rather have the name be
eof-object? .
2. I disagree that the programmer should not be able to change
the current i/o streams. The debugging problem can be trivially fixed
if the error system/debugger always installs the appropriate stream,
and this can be accomplished easily by appropriate
with-input-from-stream and with-output-from-stream.
Note that allowing the programmer to change them allows for a
cheap implementation of trasncript-on and transcript-off if the stream
objects are appropriately powerful (which they probably want to be).
There is good reason for making them functions rather thatn
variables. If they are variables, the implementation cannot easily
cash the internal components of a stream object in the appropriate
places. For example, for faster default output the implementation can
cash in the printer the procedures for printing characters and strings
to the current output-stream. If the variable is changed, the cash
has to be updated which means either that changes to some variables
are noticed (some variables are special, which I think is a bad idea),
or that the printer must check every time it is invoked. Since
with-output-from..., etc, provide ways of redirecting output, and
furthermore, a procedure set-current-output-stream! can be provided,
there is no functionality lost and the implementation has more freedom.
3. Having functions rather than special forms is in general good,
especially since we have not decided whether special form (and macro)
names are scoped in the same environment or in a different one, and
other such issues.
Note that these functions parallel
call-with-current-continuation on which we agreed at the workshop, and
the reasons are mostly the same.
4. I don't particularly care about the name for
is-character-available? (listen?), but there is an important issue
which I believe has not been raised.
On interactive streams users may have the possibility of
erasing typed characters. What happens if listen? returns true and
then the user erases the character? The program which invoked listen?
will probably attempt to read a character thinking that it will not
hang but it will. We had this bug and went to a fair amount of hair
to get it fixed.
I see two possible solutions to this:
- Listen? locks the character if it returns true. This is
ugly since read-character may not be performed for a while, and may
even be bypassed (error exit, etc.)
- Listen? is polymorphic and returns either '() or a character
object if one is available. This assumes that the set of character
objects is disjoint from the set { '() }. No further call to read is
needed. Listen? would then more appropriately be called
non-blocking-read-char. I advocate for this solution.
5. We have not talked at all about keyboard interrupts. It seems
to me that any reasonable implementation should provide a way for the
user to (at least) abort an infinite loop. It would be nice if we had
a simple standard mechanism for doing this, but implementations would
be free to have more keyborad interrupts (we currently have 5 by
default). I propose that we choose some control character (↑G, for
example) which on all implementations and unless inhibited (an editor
may want to do this) will interrupt Scheme and make it return to the
top-level read-eval-print loop.
∂17-Mar-85 1027 @MIT-MC:CPH@MIT-OZ I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 17 Mar 85 10:26:56 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 17 MAR 85 13:24:58 EST
Date: Sun, 17 Mar 1985 13:24 EST
Message-ID: <CPH.12095787388.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
Cc: Kent Dybvig <dyb%unc.csnet@CSNET-RELAY.ARPA>, scheme@MIT-MC.ARPA
Subject: I/O proposal
In-reply-to: Msg of 17 Mar 1985 11:37-EST from Bill Rozas <JINX>
Date: Sunday, 17 March 1985 11:37-EST
From: Bill Rozas <JINX>
1. Having a way to detect the end of file is needed, beyond that,
both alternatives (eof? or *eof*) can be trivially implemented on top
of the other. I don't feel strongly about either, but I tend to agree
with Kent Dybvig since I view *eof* as more flexible. If the other
option (eof?) is chosen, I would much rather have the name be
eof-object? .
I don't think that *EOF* is a good idea, for the following reason: if
the I/O primitives are expected to return this object, they will have
to return it, and if they are written in assembly or some other
non-Scheme language it would require them to do a variable reference.
Or, at the very least, to have some kind of Scheme wrapper that either
passed them the eof object, or detected that they had returned some
other object and substituted that one.
I vastly prefer the idea of a small fixed set of end of file objects,
and I wish that I had thought up the idea myself. However, I agree
that EOF-OBJECT? is a much better name.
If it is felt that there is a need for something like *EOF*, I would
feel better about having a procedural binder, something like
(WITH-EOF-OBJECT <object> (LAMBDA () ...))
which would give the implementer more freedom.
2. I disagree that the programmer should not be able to change
the current i/o streams. The debugging problem can be trivially fixed
if the error system/debugger always installs the appropriate stream,
and this can be accomplished easily by appropriate
with-input-from-stream and with-output-from-stream.
This has been my experience -- we have had this stuff running for
quite some time without problems.
∂17-Mar-85 2041 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa assertions are better than types
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 17 Mar 85 20:41:33 PST
Received: from csnet-relay by MIT-MC.ARPA; 17 MAR 85 23:40:21 EST
Received: from indiana by csnet-relay.csnet id aa08590; 17 Mar 85 23:36 EST
Date: Sun, 17 Mar 85 17:21:05 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA03798; Sun, 17 Mar 85 17:21:05 est
To: scheme@mit-mc.ARPA
Subject: assertions are better than types
Gerry's numbers proposal is the first attempt I've ever seen at
doing numbers right, and I'm very excited about it. I've become
concerned about the effectiveness of the type-restricted
operators, however, and I'd like to offer an alternative
proposal.
First of all, let me state my understanding of Gerry's proposal,
as I edited it for the Revised Revised Report. (I know it isn't
written very well -- my concern was growing as I wrote it.)
----------------------------------------------------------------
(number op) procedure
(complex op) procedure
(real op) procedure
(rational op) procedure
(integer op) procedure
These procedures take a numeric operator op and return a
procedure that acts like op except that it is restricted to
operate on numbers of the specified type and to return numbers
of the specified type. The idea of these procedures is
expressed by
(define make-type-restrictor
(lambda (type?)
(lambda (op)
(lambda args
(if (every type? args)
(let ((ans (apply op args)))
(if (type? ans)
ans
(error "Bad result from type-restricted operator")))
(error "Bad argument to type-restricted operator"))))))
(define number (make-type-restrictor number?))
(define complex (make-type-restrictor complex?))
(define real (make-type-restrictor real?))
(define rational (make-type-restrictor rational?))
(define integer (make-type-restrictor integer?))
where EVERY returns true if its first argument, a predicate, is
true of every element of its second argument, a list.
Some implementations may provide a mechanism whereby the
programmer can request that these type restriction procedures be
interpreted as assertions intended to make the code run faster
rather than as requests for type checks.
((real sqrt) 5) --> 2.236067977
((real sqrt) -1) --> error
((integer sqrt) 10) --> error
The programmer who wrote the last example probably wanted to
compute (TRUNCATE ((REAL SQRT) 10)).
[Gerry's rationale would go here.]
----------------------------------------------------------------
My objections:
1. Speaking for myself, I would not want to clutter my code
with all these type-restricted operators as I write the code,
because it would make the code less readable. (I guess
readability is more important to my debugging processes than are
type checks.) I would be willing to add type assertions when the
time came to make the code run fast. Hence for me at least, the
type restrictions would be more important as advice to the
compiler than as debugging aids.
2. The type restrictors require that all operands and the
result be of the same type. This works reasonably well for
numeric operators but is going to be awkward when the time comes
to generalize it to other operators. How am I going to tell the
compiler that the first argument to vector-ref is a vector of
strings?
3. Statically typed languages are mistaken in associating types
with variables, and Gerry is on the right track to associate
type restrictions with operators, but I think most of us would
agree that the right thing to do is to associate types with
values. That leads to my proposal, which follows:
----------------------------------------------------------------
(assert property? obj) procedure
PROPERTY? must be a total (everywhere defined) unary predicate
with no side effects. Returns obj. It is an error if PROPERTY?
is not true of obj, but implementations are not required to
detect the error.
Rationale: In interpreted code, assertions can be used to check
types, loop invariants, and other assertions. In compiled code,
calls to ASSERT have zero overhead but help the compiler to
produce better code. The ASSERT procedure is a moby
generalization of Common Lisp's special form called THE, and of
MacLisp's FIXNUM-IDENTITY and FLONUM-IDENTITY.
----------------------------------------------------------------
Examples:
Here is Gabriel's tak benchmark with type-restricted operators
as in Gerry's proposal:
(define (tak x y z)
(if (not (<? y x)) ; notice that you can't say (integer <?)
z
(tak (tak ((integer -1+) x) y z)
(tak ((integer -1+) y) z x)
(tak ((integer -1+) z) x y))))
Here it is with assertions:
(define (tak x y z)
(assert integer? x)
(assert integer? y)
(assert integer? z)
(if (not (<? y x))
z
(tak (tak (-1+ x) y z)
(tak (-1+ y) z x)
(tak (-1+ z) x y))))
You could also wrap all the references (or calls) to tak in an
integer declaration, but it's easy to see that that's
unnecessary.
Here is doubly recursive Fibonacci:
; Gerry's proposal
(define (fib n)
(if (<? n 2) ; notice again that (integer <?) won't work
n
((integer +) (fib ((integer -) n 1)) (fib ((integer -) n 2)))))
; With assertions
(define (fib n)
(assert integer? n)
(if (<? n 2)
n
(+ (assert integer? (fib (- n 1)))
(assert integer? (fib (- n 2))))))
; With a good compiler, this would suffice.
(define (fib n)
(assert integer? n)
(if (<? n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
Of course, if you really wanted fib to run fast, and you didn't
intend to use it with arguments greater than 40, and excellent
compilers were widespread, then you would probably say something
like
(define fib
(let ((fixnum?
(lambda (x)
(and (integer? x)
(not (negative? x))
(<? x 100000000)))))
(rec fib
(lambda (n)
(assert fixnum? n)
(if (<? n 2)
n
(+ (assert fixnum? (fib (- n 1)))
(assert fixnum? (fib (- n 2)))))))))
∂17-Mar-85 2054 @MIT-MC:CPH@MIT-OZ assertions are better than types
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 17 Mar 85 20:54:04 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 17 MAR 85 23:53:02 EST
Date: Sun, 17 Mar 1985 23:52 EST
Message-ID: <CPH.12095901736.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Will Clinger <willc%indiana.csnet@CSNET-RELAY.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: assertions are better than types
In-reply-to: Msg of 17 Mar 1985 17:21-EST from Will Clinger <willc%indiana.csnet at csnet-relay.arpa>
Nice! I like it.
∂17-Mar-85 2248 @MIT-MC:KMP@SCRC-STONY-BROOK assertions are better than types
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 17 Mar 85 22:47:47 PST
Received: from SCRC-STONY-BROOK by MIT-MC via Chaosnet; 18 MAR 85 01:46:45 EST
Received: from SCRC-RIO-DE-JANEIRO by SCRC-STONY-BROOK via CHAOS with CHAOS-MAIL id 198848; Mon 18-Mar-85 01:47:30-EST
Date: Mon, 18 Mar 85 01:45 EST
From: Kent M Pitman <KMP@SCRC-STONY-BROOK.ARPA>
Subject: assertions are better than types
To: willc%indiana.csnet@CSNET-RELAY.ARPA, scheme@MIT-MC.ARPA
In-Reply-To: The message of 17 Mar 85 17:21-EST from Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Message-ID: <850318014558.4.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM>
I haven't had a chance to go over the recent burst of proposals in
enough depth to comment, but will get to it.
Let me mention, though, while I'm thinking about it, that with regard to:
Date: Sun, 17 Mar 85 17:21:05 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
... Here is doubly recursive Fibonacci:
; Gerry's proposal
(define (fib n)
(if (<? n 2) ; notice again that (integer <?) won't work
n
((integer +) (fib ((integer -) n 1)) (fib ((integer -) n 2)))))
; With assertions
(define (fib n)
(assert integer? n)
(if (<? n 2)
n
(+ (assert integer? (fib (- n 1)))
(assert integer? (fib (- n 2))))))
; With a good compiler, this would suffice.
(define (fib n)
(assert integer? n)
(if (<? n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
Please be careful when writing your compilers not to copy the Maclisp bug
where:
(DEFUN F (X Y) (DECLARE (FIXNUM X Y)) (PLUS X Y))
turns into a single-instruction addition, ignoring overflow. Gerry's proposal
does not specify much of any way to get code that can do that. It was an
unfortunate mistake since when X and Y are large, the addition can overflow
and bad values can get returned (something GJS's proposal frowns on).
When we thought about this in T a long time ago, we noticed that there are
some kinds of integers which can be said in the abstract to be suitable for
machine-instruction operations. For example, things that count other things
in the address space (eg, array indices) are somehow bounded in a way that
you could usefully take advantage of. It may be useful, therefore, to create
a type called something like INDEX which is like INTEGER but is bounded by
the number of addressable things in the world. Then one can write:
(ASSERT INDEX? (+ (ASSERT INDEX? X) (ASSERT INDEX? Y)))
to get a machine-instruction addition in those cases where it is reliable.
Systems which had addressing schemes that made it impossible to place a bound
on the size of an INDEX could just treat it as synonymous with INTEGER, which
would be invisible to the user except performance-wise.
By the way, changing the subject slightly, but still on the topic of assertions,
my original proposal for T was to have PLUS and + be synonyms, but to have
operators ASSERT and MAP-ASSERT which let one write customizations such as:
(DEFINE-OPEN-CODED (+ . ARGS)
(ASSERT INTEGER? (APPLY PLUS (MAP-ASSERT INTEGER? ARGS))))
so that (+ X Y)
would be like (ASSERT INTEGER? (PLUS (ASSERT INTEGER? X) (ASSERT INTEGER? Y)))
or
(DEFINE-OPEN-CODED (INTEGER OPERATOR)
(LAMBDA ARGS (ASSERT INTEGER? (APPLY OPERATOR (MAP-ASSERT INTEGER? ARGS)))))
so that ((INTEGER +) X Y)
would be like (ASSERT INTEGER? (+ (ASSERT INTEGER? X) (ASSERT INTEGER? Y)))
I think MAP-ASSERT got lost from T somewhere along the way, but perhaps it
would be worth picking back up if people thought this sort of thing was fun.
∂18-Mar-85 1045 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Re: I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 18 Mar 85 10:45:12 PST
Received: from csnet-relay by MIT-MC.ARPA; 18 MAR 85 13:25:10 EST
Received: from unc by csnet-relay.csnet id ae00998; 18 Mar 85 13:22 EST
Received: by unc (4.12/4.7) id AA18455; Sat, 16 Mar 85 22:12:45 est
Date: Sat, 16 Mar 85 22:12:45 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8503170312.AA18455@unc>
To: scheme@mit-mc.ARPA
Subject: Re: I/O proposal
(This note should have come before the others, as it was
referenced in one of them -- sorry.)
> I disagree -- proliferation of special forms is a communicable disease.
Addition of new syntax where new syntax makes sense is never
harmful. It's much more clumsy to use a function when what
really makes sense is a proceedure. Ninety-nine times out
of a hundred people are going to type:
(with-output-to-file "fudmich"
(lambda ()
...))
Adding an extra level of complexity (not to mention an extra
level of nesting).
If we continue to use functions where syntax is appropriate,
pretty soon someone will suggest that the reader syntax
"#'exp" should mean "(lambda () exp)".
If keeping the language small is the goal, proliferation of
functions is more harmful; the ``core'' set must include only
special forms that cannot be implemented using syntactic-
extension, plus all of the functions. I can preprocess a
program on my system to take out the syntax before sending
it to you to run it on your system, but you must have the
functions I call (unless I send them all to you).
Granted, with this particular special form, the standard does
not give us enough information to write it as syntax; this is
a shortcoming in the standard, not in syntactic-extension.
..Kent
∂18-Mar-85 1049 JAR@MIT-MC I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 18 Mar 85 10:48:59 PST
Date: 18 March 1985 13:48-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: I/O proposal
To: dyb%unc.csnet @ CSNET-RELAY
cc: SCHEME @ MIT-MC
In-reply-to: Msg of Sat 16 Mar 85 22:12:45 est from Kent Dybvig <dyb%unc.csnet at csnet-relay.arpa>
Date: Sat, 16 Mar 85 22:12:45 est
From: Kent Dybvig <dyb%unc.csnet at csnet-relay.arpa>
> I disagree -- proliferation of special forms is a communicable disease.
Addition of new syntax where new syntax makes sense is never
harmful. It's much more clumsy to use a function when what
really makes sense is a proceedure. Ninety-nine times out
of a hundred people are going to type:
(with-output-to-file "fudmich"
(lambda ()
...))
Adding an extra level of complexity (not to mention an extra
level of nesting).
I would not argue strongly if you claimed that antispecialformism was a
purely religious position (although I'd wonder, since it's so strongly
held in some camps, such as the ones I belong to). One rational
argument, however, might be not necessarily language simplicity, as you
suggested, but rather, program analyzability. Any program-analyzing
program or human must know about ALL special forms in order to do things
such as free variable analysis and substitution; and there is much one
can say about a program without having ANY knowledge of the values of
free variables. So, generally speaking, special forms add to the
complexity of program analysis, whereas procedures (i.e. bindings) do
not, and therefore special forms are to be avoided.
This argument does not necessarily apply to macros (since macro forms
can be expanded), but since Essential Scheme is militant in not having a
theory of macros, that doesn't help much.
If we continue to use functions where syntax is appropriate,
pretty soon someone will suggest that the reader syntax
"#'exp" should mean "(lambda () exp)".
Actually this is not so absurd. I have from time to time toyed with the
idea of a reader syntax for (lambda () ...) in analogy to that for
(quote ...) for this very reason - the presence of such a thing would
often shoot down the conciseness arguments sometimes put forth in favor
of special forms.
Jonathan
∂18-Mar-85 1123 @MIT-MC:GJS@MIT-OZ Re: I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 18 Mar 85 11:22:38 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 18 MAR 85 14:20:44 EST
Date: Mon 18 Mar 85 14:09:28-EST
From: Gerald Jay Sussman <GJS%MIT-OZ@MIT-MC.ARPA>
Subject: Re: I/O proposal
To: dyb%unc.csnet@CSNET-RELAY.ARPA
cc: scheme@MIT-MC.ARPA
In-Reply-To: Message from "Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>" of Mon 18 Mar 85 14:02:16-EST
I think that syntax is not the right thing if we can avoid it. For
example, one can pass a procedure WITH-OUTPUT-TO-FILE as an argument
or return it as a value... We cannot do that with a syntactic form.
Thus, unless there are overwhelming reasons for introducing syntax, we
really should not do so.
-------
∂18-Mar-85 1159 @MIT-MC:GJS@MIT-OZ Re: assertions are better than types
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 18 Mar 85 11:59:28 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 18 MAR 85 14:56:49 EST
Date: Mon 18 Mar 85 14:01:07-EST
From: Gerald Jay Sussman <GJS%MIT-OZ@MIT-MC.ARPA>
Subject: Re: assertions are better than types
To: willc%indiana.csnet@CSNET-RELAY.ARPA
cc: scheme@MIT-MC.ARPA
In-Reply-To: Message from "Will Clinger <willc%indiana.csnet@csnet-relay.arpa>" of Sun 17 Mar 85 23:42:56-EST
Hi. Before you jump, I just want to clarify a few points about what I
meant by type-restricted operators -- I know I didn't say this in the
draft I sent you, but I didn't realize the scope of possible
confusion. I rspond pointwise:
Willc: Speaking for myself, I would not want to clutter my code
with all these type-restricted operators as I write the code,
because it would make the code less readable. (I guess
readability is more important to my debugging processes than are
type checks.) I would be willing to add type assertions when the
time came to make the code run fast. Hence for me at least, the
type restrictions would be more important as advice to the
compiler than as debugging aids.
GJS: I agree, usually we would not write the ugly kind of code which
is illustrated below:
(define (tak x y z)
(if (not (<? y x)) ; notice that you can't say (integer <?)
z
(tak (tak ((integer -1+) x) y z)
(tak ((integer -1+) y) z x)
(tak ((integer -1+) z) x y))))
Instead we would write something like this:
(define tak
(let ((-1+ (integer -1+))
(<? (integer <?))) ;Note that we can say this, see below!
(lambda (x y z)
(if (not (<? y x))
z
(tak (tak (-1+ x) y z)
(tak (-1+ y) z x)
(tak (-1+ z) x y))))))
Presumably, with a good compiler it would be just as efficient to
write:
(define (tak x y z)
(let ((-1+ (integer -1+))
(<? (integer <?))) ;Note that we can say this, see below!
(if (not (<? y x))
z
(tak (tak (-1+ x) y z)
(tak (-1+ y) z x)
(tak (-1+ z) x y)))))
Willc: The type restrictors require that all operands and the
result be of the same type. This works reasonably well for
numeric operators but is going to be awkward when the time comes
to generalize it to other operators. How am I going to tell the
compiler that the first argument to vector-ref is a vector of
strings?
Willc: These procedures take a numeric operator op and return a
procedure that acts like op except that it is restricted to
operate on numbers of the specified type and to return numbers
of the specified type.
GJS: The type restrictions are not intended to be simply error-checking
on the type of the inputs and outputs, but rather to be an entry to a
more coherent system built on the numerical tower. The idea is that
for each kind of number there is a set of appropriate kinds of operations
that make sense for it. For example, the INTEGERS are a ring, hence they
do not support arbitrary division. This does not stop us from defining
"/" for the INTEGERS to be anything we like, such as an entry to higher
types on the tower. Additionally, I am not even attempting to clarify
the types for things like strings or vectors of strings, since they do
not have the mathematical structure of numbers... This is trying to be a
coherent theory about numbers, rather than an incoherent theory of
everything.
For example, Hal and I have been hacking a new version of generic
arithmetic based on these principles -- I include a fragment for your
amusement. Basically, there is an operation table, and "restrictions"
like INTEGER are things that transform the generic operator, like +,
into the actual operation from the table.
The following code creates a "rational package" for a
given RING, the new objects have type FIELD.
;;; Rational operations generator
(define (make-rational-operations! ring field)
(let ((+r (ring +)) (-r (ring -)) (*r (ring *)) (negate-r (ring negate))
(=r (ring =)) (gcd (ring gcd)) (quotient (ring quotient))
(sign-r (ring sign)) (one-r (ring 'one)) (zero-r (ring 'zero)))
(define (make-rational n d)
(let ((s (sign-r d)))
(cond ((=r one-r s)
(cons '*numeric-type*
(cons field (cons n d))))
((=r zero-r s)
(error "Bad rational construction" field (list n d)))
(else
(cons '*numeric-type*
(cons field
(cons (quotient n s)
(quotient d s))))))))
(define numer caddr)
(define denom cdddr)
(define (+←rational x y)
(let ((d1 (gcd (denom x) (denom y))))
(if (=r one-r d1) ;GIGO
(make-rational (+r (*r (numer x) (denom y))
(*r (denom x) (numer y)))
(*r (denom x) (denom y)))
(let ((dx/d1 (quotient (denom x) d1)))
(let ((tem (+r (*r (quotient (denom y) d1) (numer x))
(*r dx/d1 (numer y)))))
(let ((d2 (gcd tem d1)))
(make-rational (quotient tem d2)
(*r dx/d1
(quotient (denom y) d2)))))))))
(define (-←rational x y)
(+←rational x (make-rational (negate-r (numer y)) (denom y))))
(define (*←rational x y)
(let ((d1 (gcd (numer x) (denom y)))
(d2 (gcd (numer y) (denom x))))
(make-rational (*r (quotient (numer x) d1)
(quotient (numer y) d2))
(*r (quotient (denom x) d2)
(quotient (denom y) d1)))))
(define (/←rational x y)
(*←rational x (make-rational (denom y) (numer y))))
(define (=←rational x y)
(and (=r (numer x) (numer y)) (=r (denom x) (denom y))))
(define (negate-rational x)
(make-rational (negate-r (numer x)) (denom x)))
(define (recip-rational x)
(make-rational (denom x) (numer x)))
(define (raise i)
(make-rational i one-r))
(put-coercion! raise ring field)
(put-op! (raise zero-r) 'zero field)
(put-op! (raise one-r) 'one field)
(put-op! +←rational + field)
(put-op! -←rational - field)
(put-op! *←rational * field)
(put-op! /←rational / field)
(put-op! =←rational = field)
(put-op! negate-rational negate field)
(put-op! recip-rational recip field)
(put-op! (lambda (x) (sign-r (numer x))) sign field)
(put-op! numer numerator field)
(put-op! denom denominator field)
))
;;;Now we can use this to define the rationals over integers
(define (rational op) (get-op op rational))
(define (rational? x)
(or (integer? x)
(eq? (numeric-type x) rational)))
(make-rational-operations! integer rational 'rational)
;;;For these particular rationals, we may also want some additional
;;;operations that are not sensible for arbitrary rationals, e.g.,
;;;based upon polynomial rings. For example:
(define (raise-rational-unary-operation op)
(lambda (x) (op (rational->real x))))
(put-op! (raise-rational-unary-operation sqrt) sqrt rational)
(put-op! (raise-rational-unary-operation sin) sin rational)
(put-op! (raise-rational-unary-operation cos) cos rational)
(put-op! (raise-rational-unary-operation tan) tan rational)
(put-op! (raise-rational-unary-operation real-part) real-part rational)
(put-op! (raise-rational-unary-operation imag-part) imag-part rational)
(put-op! (raise-rational-unary-operation magnitude) magnitude rational)
(put-op! (raise-rational-unary-operation angle) angle rational)
-------
∂18-Mar-85 1210 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa Arithmetic overflow
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 18 Mar 85 12:09:58 PST
Received: from csnet-relay by MIT-MC.ARPA; 18 MAR 85 15:08:58 EST
Received: from indiana by csnet-relay.csnet id a001575; 18 Mar 85 14:38 EST
Date: Mon, 18 Mar 85 10:48:24 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA03030; Mon, 18 Mar 85 10:48:24 est
To: scheme@mit-mc.ARPA
Subject: Arithmetic overflow
Kent Pitman points out:
>Please be careful when writing your compilers not to copy the Maclisp bug
>where:
>
>(DEFUN F (X Y) (DECLARE (FIXNUM X Y)) (PLUS X Y))
>
>turns into a single-instruction addition, ignoring overflow. Gerry's proposal
>does not specify much of any way to get code that can do that. It was an
>unfortunate mistake since when X and Y are large, the addition can overflow
>and bad values can get returned (something GJS's proposal frowns on).
I agree whole-heartedly. Like Gerry's proposal, the ASSERT procedure does
not give the programmer the ability to specify that overflow is to be ignored,
though it can be used to assert that a result is within a certain range.
My last fibonacci example was perhaps too subtle. In computing (fib 40), the
arguments to + are always less than 100000000 (the constant appearing in the
fixnum? procedure), but the result is greater than 100000000. A compiler that
assumes that the result of an addition is never greater than the operands is
simply buggy.
Peace, Will Clinger
∂18-Mar-85 1545 @MIT-MC:linus!ramsdell@mitre-bedford Pointer-less stack allocated arrays.
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 18 Mar 85 15:39:44 PST
Received: from mitre-bedford by MIT-MC.ARPA; 18 MAR 85 18:38:27 EST
Date: 18 Mar 1985 18:36:50-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA07064; Mon, 18 Mar 85 15:17:32 est
Date: Mon, 18 Mar 85 15:17:32 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503182017.AA07064@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: Pointer-less stack allocated arrays.
I recently visited Harvard and had an interesting
conversation with Stavros Macrakis. He is an
Ada proponent with considerable experience with
Lisp, in particular, MacLisp. He was very active
in the Macsyma project and gained much knowledge
about MacLisp's implementation.
I brought up the subject of extensible languages
in reference to Richard Schooler's masters thesis
called "Partial Evaluation as a means of Language
Extensibility", MIT/LCS/TR-324, August 1984. The
thesis suggests that Scheme makes a good intermediate
language; very suitable for partial evaluation.
Stavros immediately rejected the notion that Scheme
makes a good intermediate language because its model
of data is too general. For example, consider the
task of taking the dot product of two vectors represented
by two arrays of floating point numbers. Since arrays can
be returned from the function in which they are created,
they must be allocated from the heap. Since garbage collection
can change the origin of the array, all references to elements
in the array must be accompanied with a reference to the array
header. Thus the compiled code for Scheme can never be as
good as that produced by an Ada compiler said Starvos.
Many years ago, I asked Jonathan Rees if the T compiler could
place arrays on the stack when appropriate and eliminate the
unneccessary indirection in numerical arrays by replacing
pointers to floating point numbers with the actual numbers
as the array elements. He claimed compiler declarations
would make this possible, but had many other more pressing issue
to worry about in regards to the T compiler. I am wondering
if there is interest in using ASSERT to allow the elimination of
many pointers in some programs.
John
∂18-Mar-85 2056 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa Re: I/O proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 18 Mar 85 20:55:51 PST
Received: from csnet-relay by MIT-MC.ARPA; 18 MAR 85 23:54:51 EST
Received: from indiana by csnet-relay.csnet id ab04361; 18 Mar 85 23:38 EST
Date: Mon, 18 Mar 85 16:46:58 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA08003; Mon, 18 Mar 85 16:46:58 est
To: scheme@mit-mc.ARPA
Subject: Re: I/O proposal
We thank everyone for their comments on the I/O proposal. Here
are our responses.
>Also, I think that you should have both "STREAM?" and its components
>"INPUT-STREAM?" and "OUTPUT-STREAM?", because it makes more
>information available without really constraining the implementation
>in any fundamental way. Clearly bidirectional streams can satisfy
>both predicates.
Agreed. Any dissent?
----------------------------------------------------------------
>The only objection I have is the
>use of the word STREAM for the IO stuff. My problem is that we used that
>word all through chapter 3 of our book to mean the functional programming
>idea of (potentially) infinite sequence. It will be very painful to change
>that. I propose that the word be changed to one of CHANNEL, PIPE, PORT, TUBE,
>or any other appropriate euphemism. I believe that my use of the word STREAM
>is consistent with that of other authors on functional programming.
>-- I oppose the term "stream" and thus the names STREAM?, CURRENT-INPUT-
>STREAM, etc., for the reasons Gerry gave. We use "port".
Good point, so the names will change as follows:
old name new name
stream? input-port?
output-port?
current-input-stream current-input-port
current-output-stream current-output-port
close-input-stream close-input-port
close-output-stream close-output-port
----------------------------------------------------------------
>-- What happened to the names PRIN1 and PRINC? Are your WRITE and DISPLAY
>meant to be equivalent, respectively, to PRIN1 and PRINC? As I understand
>page 382 of the Common LISP (CL) book, your WRITE is not incompatible with
>CL's. Likewise, CL doesn't seem to have a DISPLAY. However, I am bothered
>by my intuition that DISPLAY should be a terminal-oriented operation.
>
> Bottom line: I vote to go with WRITE and DISPLAY, but the names PRIN1
>and PRINC should be reserved as well (as optional aliases). The PRINT
>operation should also be optional, with the CL-compatible meaning we agreed
>on at the workshop.
Yes, WRITE and DISPLAY correspond to Common Lisp's PRIN1 and
PRINC. For that matter they correspond to T's PRINT and DISPLAY,
and to Scheme-84's DISPLAY and PRINT. Common Lisp's WRITE takes
a stream as a keyword argument whereas Scheme's WRITE takes a
port as an optional argument. If that incompatibility doesn't
bother you then it certainly doesn't bother us.
PRINC and PRINT are used in the Abelson and Sussman book, but we
don't think they deserve or need formal status.
----------------------------------------------------------------
>2. "A different set of procedures will be needed to create streams from
>and to strings, and the closing procedures should still work on them.
>It seems that closing a string output stream should yield a string, but
>it isn't clear what should be returned when a file output stream is
>closed."
>
>I don't understand this at all. The phrase "create streams from and to
>strings" is rather difficult to parse, which doesn't help.
Scheme doesn't have anything comparable to Common Lisp's
READ-FROM-STRING, WRITE-TO-STRING, WITH-INPUT-FROM-STRING, and
WITH-OUTPUT-TO-STRING. When we get around to adding those
capabilities, we will want to package the strings up to look like
ordinary I/O ports that can be passed as the optional argument to
READ and WRITE. It appears that the designers of Common Lisp
didn't quite figure out how they wanted to do it either.
----------------------------------------------------------------
>3. Are with-input-from-file and with-output-from-file the only way to
>change the value of (current-input-stream) and (current-output-stream) ?
>If so, shouldn't they be essential ?
We agree that this is somewhat inconsistent, but there are
difficulties involved with specifying the correct semantics for
WITH-INPUT-FROM-FILE and WITH-OUTPUT-TO-FILE, as well as difficulties
involved with implementing them correctly, so for the time being...
WITH-INPUT-FROM-FILE and WITH-OUTPUT-TO-FILE are the only ways
defined in the proposal to change the default input or output
ports. Implementations may feel that the default ports should
always be the keyboard and screen, or they may prefer alternative
ways to change the default ports. The main reason for making
WITH-INPUT-FROM-FILE and WITH-OUTPUT-TO-FILE optional rather than
essential, however, is that we are not certain of the best way
for them to interact with escape procedures, and it seems a good
idea to keep uncertainties like that out of the essential
language until we understand them better.
----------------------------------------------------------------
>-- DISPLAY-CHAR seems to be a redundant, restricted form of DISPLAY. Since
>DISPLAY is essential, DISPLAY-CHAR should be dropped.
At the workshop it was emphasized that characters may overlap
with numbers, strings, or what have you. If characters are just
numbers, then (DISPLAY #\SPACE) will print something like "32"
whereas (WRITE-CHAR #\SPACE) will print " " (without the double
quotes, of course).
>I wonder why you chose the name "DISPLAY-CHAR" rather than
>"WRITE-CHAR"? I prefer "WRITE-CHAR" because it has no connotations of
>display terminals, or of being viewed by a human; it says, simply,
>that the character was written down somewhere.
WRITE-CHAR it is.
----------------------------------------------------------------
>I don't see any reason for LOAD and CURRENT-INPUT-STREAM to interact,
>and I think it is much better for them not to. If they don't interact
>you have a much better invariants on each, e.g.: doing LOAD on a file is
>the same as doing LOAD on a file consisting of the string "(begin "
>appended to the file appended to the string ")".
We agree entirely, and are flushing the sentence in question.
----------------------------------------------------------------
>-- The name LISTEN? also is slightly unintuitive to me; how about INPUT?,
>or MORE-INPUT?, or something with "peek" in it.
LISTEN? is named after the LISTEN predicate in Common Lisp.
"Peek" calls to mind MacLisp's TYIPEEK, which is unrelated.
We're willing to change the name, and the following are the leading
candidates:
CHAR-READY?
INPUT-READY?
Please send your votes to brooks@indiana before 25 March.
----------------------------------------------------------------
>-- Does READ-CHAR wait for interactive input or return an eof token if
>nothing has been buffered up from the keyboard (or comm device, etc)?
It waits.
----------------------------------------------------------------
>-- With my Pascal (and English) background, I can't help but think of
>features named with "with", like WITH-INPUT-FROM-FILE, as syntax, not
>procedures. [Did you notice how I began the previous sentence?] I would
>prefer a special form: (WITH-INPUT-FROM-FILE <file-name> exp ...). This is
>more consistent with CL's macro WITH-INPUT-FROM-STRING. The same goes for
>WITH-OUTPUT-FROM-FILE.
We prefer procedures to special forms, and we followed MIT's
names here. It is hard to come up with good names for these
procedures.
Thanks again to all who are commenting on the proposals.
Gary Brooks and Will Clinger
∂19-Mar-85 0456 @MIT-MC:forwarder@CSNET-SH.ARPA Message a011267 -- long message to scheme@mit-mc
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 19 Mar 85 04:56:45 PST
Received: from CSNET-SH by MIT-MC.ARPA; 19 MAR 85 07:55:45 EST
To: scheme@MIT-MC.ARPA
cc: willc%indiana.csnet@CSNET-SH.ARPA
Subject: Message a011267 -- long message to scheme@mit-mc
Reply-to: cic@CSNET-SH.ARPA
Date: 19 Mar 85 07:45:58 EST (Tue)
From: "Charlotte D. Mooers" <postmaster@CSNET-SH.ARPA>
This message was rejected by mit-mc for the following reason:
'Message is too large to mail; use FTP.'
Since FTP (file transfer protocol) is not possible between indiana
and mit-mc, I have split up the message into three sections of
1000, 1000 and 695 lines each, which I will send separately.
In the future, please agree on a limit to the length of file that
you will transmit by mail to mit-mc.
---Charlotte Mooers
CSNET Staff
∂19-Mar-85 0459 @MIT-MC:forwarder@CSNET-SH.ARPA Message a011267 LONG message - part 1
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 19 Mar 85 04:58:56 PST
Received: from CSNET-SH by MIT-MC.ARPA; 19 MAR 85 07:56:10 EST
To: scheme@MIT-MC.ARPA
Subject: Message a011267 LONG message - part 1
Reply-to: cic@CSNET-SH.ARPA
Date: 19 Mar 85 07:48:45 EST (Tue)
From: "Charlotte D. Mooers" <postmaster@CSNET-SH.ARPA>
Received: from csnet-relay.arpa by CSNET-SH.ARPA id a028166; 18 Mar 85 13:26 EST
Date: Mon, 18 Mar 85 10:55:42 EST
From: CSNET-RELAY Memo Service (MMDF) <mmdf@CSNET-RELAY.ARPA>
Subject: Failed mail (msg.a011267)
Sender: mmdf@CSNET-RELAY.ARPA
To: Postmaster@CSNET-RELAY.ARPA
Your message could not be delivered to
'scheme@mit-mc.ARPA (host: mit-mc.arpa) (queue: smtp)' for the following
reason: ' Message is too large to mail; use FTP.'
Your message follows:
Received: from indiana by csnet-relay.csnet id a011267; 18 Mar 85 9:36 EST
Date: Mon, 18 Mar 85 01:24:29 est
From: willc@Indiana (Will Clinger)
Received: by iuvax.UUCP; id AA06606; Mon, 18 Mar 85 01:24:29 est
To: scheme@mit-mc
Subject: DRAFT of Revised Revised Report (LONG message)
Here is the DRAFT of the final report on the Brandeis workshop.
It is missing all its appendices, and a couple of sections that
deal with the lexical syntax of numbers need more work. Please
read it and tell me what you think. We'd like to have your
comments by 1 April so we can send it to press.
The font information has been stripped for posting to
scheme@mit-mc. Some ambiguities probably result, but please don't
get upset about them.
If you have anything more to say about Chris Hanson's work on
strings, please say it soon. We'd like to include Chris's work
in this report.
-- Will Clinger
willc@indiana
Table of Contents
Part I: Introduction to Scheme
I.0 Brief history of Scheme
I.1 Syntax of Scheme
I.2 Semantics of Scheme
Part II: A catalog of Scheme
II.0 Notational conventions
II.1 Special forms
II.2 Booleans
II.3 Equivalence predicates
II.4 Pairs and lists
II.5 Symbols
II.6 Numbers (part 1)
II.7 Numbers (part 2)
II.8 Strings
II.9 Vectors
II.10 The object table
II.11 Procedures
II.12 Ports
II.13 Input
II.14 Output
References
Index (not yet ready)
!Acknowledgements
This report is primarily the work of a group of people who met
at Brandeis University for two days in October 1984. The
participants at that workshop were Hal Abelson (MIT), Norman
Adams (Yale), David Bartley (Texas Instruments), Gary Brooks,
(Texas Instruments, Indiana University), William Clinger
(Indiana University), Dan Friedman (Indiana University), Robert
Halstead (MIT), Chris Hanson (MIT), Chris Haynes (Indiana
University), Eugene Kohlbecker (Indiana University), Don Oxley
(Texas Instruments), Jonathan Rees (MIT), Bill Rozas (MIT),
Gerald Sussman (MIT), and Mitchell Wand (Indiana University,
Brandeis). Kent Pitman (MIT) made valuable contributions to the
agenda for the workshop but was unable to attend the sessions.
We would like also to thank the following people for their
comments and criticisms in the months following the workshop:
Kent Dybvig, Andy Freeman, Yekta Gursel, Paul Hudak, Chris
Lindblad, Guy Steele Jr.
We thank Dan Friedman and Chris Haynes for permission to use
text from the Scheme 311 Version 4 reference manual. We
acknowledge the influence of manuals for MIT Scheme, T, Scheme
84, and Common Lisp.
!Part I: Introduction to Scheme
I.0 Brief history of Scheme
Scheme is a programming language invented by Guy Lewis Steele Jr
and Gerald Jay Sussman. It is a statically scoped dialect of
Lisp with an exceptionally clear and simple semantics.
The first description of Scheme was written in 1975 [\ref]. A
Revised Report [\ref] appeared in 1978, which described the
evolution of the language as its MIT implementation was upgraded
to support an innovative compiler [\ref]. Three distinct
projects began in 1981 and 1982 to use variants of Scheme for
courses at MIT, Yale, and Indiana University [\ref, ref, ref].
An excellent introductory computer science textbook using Scheme
was published in 1984 [\ref].
As might be expected of a language used primarily for education
and research, Scheme has always evolved rapidly. This was no
problem when Scheme was used only within MIT, but as Scheme
became more widespread local subdialects began to diverge until
students and researchers occasionally found it difficult to
understand code written at other sites. Fifteen representatives
of the major implementations of Scheme therefore met in October
1984 to work toward a better and more widely accepted standard
for Scheme. This paper reports their unanimous recommendations
augmented by committee work in the areas of input/output and
arithmetic.
Scheme shares with Common Lisp [\ref] the goal of a core
language common to several implementations. Scheme differs from
Common Lisp in that the purpose of the common language has as
much to do with porting ideas as with porting code. It is
appropriate therefore that Scheme is much smaller, is less
pervasively specified, and will evolve faster than Common Lisp.
!I.1 Syntax
Formal definitions of the lexical and context-free syntaxes of
Scheme will be added as appendices.
Identifiers
Most identifiers allowed by other programming languages are also
acceptable to Scheme. The precise rules for forming identifiers
vary among implementations of Scheme, but in all implementations
a sequence of characters that contains no special characters and
begins with a character that cannot begin a number is an
identifier. There may be other identifiers as well, and in
particular the following are identifiers:
+ - 1+ -1+
It is guaranteed that the following characters cannot begin a
number, so identifiers other than the four listed above should
begin with one of:
a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
! $ % & * / : < = > ? ~
Subsequent characters of the identifier should be drawn from:
a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9
! $ % & * / : < = > ? ↑ ← . ~
The case in which the letters of an identifier are typed is
immaterial. For example, Foo is the same identifier as FOO.
The following characters are special, and should never be used
in an identifier:
) ( ] [ } { " ; blank
Scheme deliberately does not specify whether the following
characters can be used in identifiers:
# ' ` , @ \ |
Rationale: Some implementations might want to use backwhack ( \)
and vertical bar ( | ) as in Common Lisp. As for the others
there are two schools of thought. One school argues that
disallowing special characters in identifiers allows the
computer to catch more typing errors. The other school agrees
only for special characters that come in pairs, because errors
that involve only the unpaired special characters are easy to
see.
Numbers
For a description of the notations used for numbers, see section
II.7. A concise summary of the notations used to write numbers
will be added to this section, and a formal description will be
part of the appendix on lexical syntax.
Comments
A semicolon indicates the start of a comment. The comment
continues to the end of the line on which the semicolon appears.
Comments are invisible to Scheme, but the end of the line is
visible as whitespace. This prevents a comment from appearing
in the middle of an identifier or number. Comments may appear
inside a string that extends over more than one line, but it is
probably a bad idea to write such strings because their contents
are implementation-dependent.
Other notations
Left and right parentheses are used for grouping and to notate
lists as described in section II.4. Left and right square
brackets and curly braces are not used in Scheme right now but
are reserved for unspecified future uses.
The quote (') and backquote (`) characters are used to indicate
constant or almost-constant data as described in section II.1.
The comma is used together with the backquote, and the atsign
(@) is used together with the comma.
The doublequote character is used to notate strings as described
in section II.8.
The sharp sign (octathorp) is used for a variety of purposes
depending on the character that follows it. A sharp sign
followed by a left parenthesis signals the beginning of a
vector, as described in section II.9. A sharp sign followed by
an exclamation point is used to notate one of the special values
#!true, #!false, and #!null. A sharp sign followed by a
backslash is used to notate characters as described in section
II.8. A sharp sign followed by any of a number of letters is
used to notate numbers as described in section II.7.
Context free grammar for Scheme
The following grammar is ambiguous because a <special form>
looks like a <procedure call>. Some implementations resolve the
ambiguity by reserving the identifiers that serve as keywords of
special forms, while other implementations allow the keyword
meaning of an identifier to be shadowed by lexical bindings.
<expression> ::= <constant>
| <identifier>
| <special form>
| <procedure call>
<constant> ::= <numeral> | #!true | #!false | #!null
| (quote <datum>) | '<datum>
<special form> ::= (<keyword> ...)
<procedure call> ::= (<expression> <arguments>)
<arguments> ::= <empty> | <expression> <arguments>
<datum> stands for any written representation of a Scheme
object, as described in the sections that follow. <identifier>
and <numeral> have already been described informally. <special
form> stands for one of the special forms whose syntax is
described in section II.1. For uniformity the other kinds of
expressions are also described in that section as though they
were special forms.
!I.2 Semantics
The formal semantics of Scheme will be the subject of an
appendix to be added. The detailed informal semantics of Scheme
is the subject of Part II. This section gives a quick review of
Scheme's major characteristics.
Scheme is a statically scoped programming language, meaning that
each use of an identifier is associated with a lexically
apparent binding of that identifier. In this respect Scheme is
like Algol 60, Pascal, and C but unlike dynamically scoped
languages such as APL and traditional Lisp.
Scheme has latent as opposed to manifest types, which means that
types are associated with values (also called objects) rather
than with variables. (Some authors refer to languages with
latent types as weakly typed or dynamically typed languages.)
Other languages with latent types are APL, Snobol, and other
dialects of Lisp. Languages with manifest types (sometimes
referred to as strongly typed or statically typed languages)
include Algol 60, Pascal, and C.
All objects created in the course of a Scheme computation,
including all procedures and variables, have unlimited extent.
This means in effect that no Scheme object is ever destroyed.
The reason that implementations of Scheme do not (usually!) run
out of storage is that they are permitted to reclaim the storage
occupied by an object if they can prove mathematically that the
object cannot possibly matter to any future computation. Scheme
is a practical programming language only because there exist
fairly efficient "garbage collection" algorithms for performing
these proofs. Other languages in which most objects have
unlimited extent include APL and Common Lisp.
Scheme procedures are objects in their own right. Procedures
can be created dynamically, stored in data structures, returned
as results of procedures, and so on. Other languages with these
properties include Common Lisp, ML, and KRC.
Arguments to Scheme procedures are always passed by value, which
means that the actual argument expressions are evaluated before
the procedure actually gains control, whether the procedure
needs the result of the evaluation or not. ML, C, and APL are
three good examples of other languages that always pass
arguments by value. KRC is a good example of a language that
passes arguments by name, so that an argument expression is
evaluated only if its value is needed by the procedure.
!Part II: A catalog of Scheme
II.0 Notational conventions
This part of the report is a catalog of the special forms and
procedures that make up Scheme. The special forms are described
in section II.1, and the procedures are described in the
following sections. Each section is organized into entries,
with one entry (usually) for each special form or procedure.
Each entry begins with a header line that includes the name of
the special form or procedure in bold face type within a
template for the special form or a call to the procedure. The
names of the arguments to a procedure are italicized, as are the
syntactic components of a special form. A notation such as
expr ...
indicates zero or more occurrences of expr, and so
expr1 expr2 ...
indicates at least one expr.
At the right of the header line one of the following categories
will appear:
special form
constant
variable
procedure
essential special form
essential constant
essential variable
essential procedure
A special form is a syntactic class of expressions, usually
identified by a keyword. A constant is something that is
lexically recognizable as a constant. A variable is an
identifier that is bound to a location in which values (also
called objects) can be stored. Those variables that initially
hold procedure values are identified as procedures.
Implementations are free to omit features of Scheme or to add
extensions, provided the extensions are not in conflict with the
language reported here. It is guaranteed, however, that every
implementation of Scheme will support the essential special
forms, constants, variables, and procedures.
Any Scheme value can be used as a boolean expression for the
purposes of a conditional test. As explained in section II.2,
most values count as true, but a few -- notably #!false -- count
as false. This manual uses the word "true" to refer to any
Scheme value that counts as true in a conditional expression,
and the word "false" to refer to any Scheme value that counts as
false.
!II.1. Special forms
Identifiers have two uses within Scheme programs. When an
identifier appears within a quoted constant (see quote), it is
being used as data as described in the section on symbols.
Otherwise it is being used as a name. There are two kinds of
things that an identifier can name in Scheme: special forms and
variables. A special form is a syntactic class of expressions,
and an identifier that names a special form is called the
keyword of that special form. A variable, on the other hand, is
a location where a value can be stored. An identifier that
names a variable is said to be bound to that location. The set
of all such bindings in effect at some point in a program is
known as the environment in effect at that point.
Certain special forms are used to allocate storage for new
variables and to bind identifiers to those new variables. The
most fundamental of these binding constructs is the lambda
special form, because all other binding constructs can be
explained in terms of lambda expressions. The other binding
constructs are the let, let*, letrec, internal definition (see
define), rec, define!, defrec!, and do special forms.
Like Algol or Pascal, and unlike most other dialects of Lisp
except for Common Lisp, Scheme is a statically scoped language
with block structure. To each place where an identifier is
bound in a program there corresponds a region of the program
within which the binding is effective. The region varies
according to the binding construct that establishes the binding;
if the binding is established by a lambda expression, for
example, then the region is the entire lambda expression. Every
use of an identifier in a variable reference or assignment
refers to the binding of the identifier that set up the
innermost of the regions containing the use. If there is no
binding of the identifier whose region contains the use, then
the use refers to the binding for the identifier that was in
effect when Scheme started up, if any; if there is no binding
for the identifier, it is said to be unbound.
variable essential special form
An expression consisting of an identifier that is not the
keyword of a special form is a variable reference. The value
obtained for the variable reference is the value stored in the
location to which variable is bound. An error is signalled if
variable is unbound.
(procedure arg1 ...) essential special form
A list of expressions whose first element is not the keyword of
a special form indicates a procedure call. The procedure and
argument expressions are evaluated and the procedure is passed
the values of the argument expressions. In constrast to other
dialects of Lisp the order of evaluation is not specified, and
the procedure expression and the argument expressions are always
evaluated in exactly the same way.
(+ 3 4) --> 7
((if #!false + *) 3 4) --> 12
(quote constant) essential special form
'constant essential special form
Evaluates to constant. This notation is used to include literal
constants in Scheme code.
(quote a) --> a
(quote #(a b c)) --> #(a b c)
(quote (+ 1 2)) --> (+ 1 2)
(quote constant) may be abbreviated as 'constant. The two
notations are equivalent in all respects.
'a --> a
'#(a b c) --> #(a b c)
'(+ 1 2) --> (+ 1 2)
'(quote a) --> (quote a)
''a --> (quote a)
Numbers, strings, and the constants #!true, #!false, and #!null
need not be quoted.
'"abc" --> "abc"
"abc" --> "abc"
'145932 --> 145932
145932 --> 145932
'#!true --> #!true
#!true --> #!true
(lambda (var1 ...) expr) essential special form
Each var must be an identifier. The lambda expression evaluates
to a procedure with formal argument list (var1 ...) and
procedure body expr. The environment in effect when the lambda
expression was evaluated is remembered as part of the procedure.
When the procedure is later called with some actual arguments,
the environment in which the lambda expression was evaluated
will be extended by binding the identifiers in the formal
argument list to fresh locations, the corresponding actual
argument values will be stored in those locations, and expr will
then be evaluated in the extended environment. The result of
expr will be returned as the result of the procedure call.
(lambda (x) (+ x x)) --> #<PROCEDURE>
((lambda (x) (+ x x)) 4) --> 8
(define reverse-subtract
(lambda (x y) (- y x))) --> reverse-subtract
(reverse-subtract 7 10) --> 3
(define foo
(let ((x 4))
(lambda (y) (+ x y)))) --> foo
(foo 6) --> 10
(lambda (var1 ...) expr1 expr2 ...) essential special form
Equivalent to (lambda (var1 ...) (begin expr1 expr2 ...)).
(lambda var expr1 expr2 ...) essential special form
Returns a procedure that when later called with some arguments
will bind var to a fresh location, convert the sequence of
actual arguments into a list, and store that list in the binding
of var.
((lambda x x) 3 4 5 6) --> (3 4 5 6)
One last variation on the formal argument list provides for a
so-called rest argument. If a space/dot/space sequence precedes
the last argument in the formal argument list, then the value
stored in the binding of the last formal argument will be a list
of the actual arguments left over after all the other actual
arguments have been matched up against the formal arguments.
((lambda (x y . z) z) 3 4 5 6) --> (5 6)
(if condition consequent alternative) essential special form
(if condition consequent) essential special form
First evaluates condition. If it yields a true value (see
section II.2), then consequent is evaluated and its value is
returned. Otherwise alternative is evaluated and its value is
returned. If no alternative is specified, then the if
expression is evaluated only for its effect, and the result of
the expression is unspecified.
(if (>? 3 2) 'yes 'no) --> yes
(if (>? 2 3) 'yes 'no) --> no
(if (>? 3 2) (- 3 2) (+ 3 2)) --> 1
(cond clause1 clause2 ...) essential special form
Each clause must be a list of one or more expressions. The
first expression in each clause is a boolean expression that
serves as the guard for the clause. The guards are evaluated in
order until one of them evaluates to a true value (see section
II.2). When a guard evaluates true, then the remaining
expressions in its clause are evaluated in order, and the result
of the last expression in the selected clause is returned as the
result of the entire expression. If the selected clause
contains only the guard, then the value of the guard is returned
as the result. If all tests evaluate to false values, then the
result of the conditional expression is unspecified.
(cond ((>? 3 2) 'greater)
((<? 3 2) 'less)) --> greater
The special keyword else may be used as a guard to obtain the
effect of an otherwise clause.
(cond ((>? 3 3) 'greater)
((<? 3 3) 'less)
(else 'equal)) --> equal
The above forms for the clauses are essential. Some
implementations support yet another form of clause such that
(cond (form1 => form2) ...)
is equivalent to
(let ((form1←result form1)
(thunk2 (lambda () form2))
(thunk3 (lambda () (cond ...))))
(if form1←result
((thunk2) form1←result)
(thunk3)))
(case expr clause1 clause2 ...) special form
Each clause is a list whose first element is a selector followed
by one or more expressions. Each selector should be a list of
values. The selectors are not evaluated. Instead expr is
evaluated and its result is compared against successive
selectors using the memv procedure until a match is found. Then
the expressions in the selected clause are evaluated from left
to right and the result of the last expression in the clause is
returned as the result of the case expression. If no selector
matches then the result of the case expression is unspecified.
(case (* 2 3)
((2 3 5 7) 'prime)
((1 4 6 8 9) 'composite)) --> composite
(case (car '(c d))
((a) 'a)
((b) 'b)) --> unspecified
The special keyword else may be used as a selector to obtain the
effect of an otherwise clause.
(case (car '(c d))
((a e i o u) 'vowel)
((y) 'y)
(else 'consonant)) --> consonant
(and expr1 ...) special form
Evaluates the exprs from left to right, returning false as soon
as one evaluates to a false value (see section II.2). Any
remaining expressions are not evaluated. If all the expressions
evaluate to true values, the value of the last expression is
returned.
(and (=? 2 2) (>? 2 1)) --> #!true
(and (=? 2 2) (<? 2 1)) --> #!false
(and 1 2 'c '(f g)) --> (f g)
(or expr1 ...) special form
Evaluates the exprs from left to right, returning the value of
the first expr that evaluates to a true value (see section
II.2). Any remaining expressions are not evaluated. If all
expressions evaluate to false values, false is returned.
(or (=? 2 2) (>? 2 1)) --> #!true
(or (=? 2 2) (<? 2 1)) --> #!true
(or #!false #!false #!false) --> #!false
(or (memq 'b '(a b c)) (/ 3 0)) --> (b c)
(let ((var1 form1) ...) expr1 expr2 ...) essential special form
Evaluates the forms in the current environment (in some
unspecified order), binds the vars to fresh locations holding
the results, and then evaluates the exprs in the extended
environment, returning the value of the last one. Each binding
of a var has expr1 expr2 ... as its region.
(let ((x 2)
(y 3))
(* x y)) --> 6
(let ((x 2)
(y 3))
(let ((foo (lambda (z)
(+ x y z)))
(x 7))
(foo 4))) --> 9
let and letrec give Scheme a block structure. The difference
between let and letrec is that in a let the forms are not within
the regions of the vars being bound. See letrec.
Some implementations of Scheme permit a "named let" syntax in
which
(let name ((var1 form1) ...) expr1 expr2 ...)
is equivalent to
((rec name (lambda (id1 ...) expr1 expr2 ...))
form1 ...)
(let* ((var1 form1) ...) expr1 expr2 ...) special form
Similar to let, but the bindings are performed sequentially from
left to right and the region of a binding indicated by (var
form) is that part of the let* expression to the right of the
binding. Thus the second binding is done in an environment in
which the first binding is visible, and so on.
(letrec ((var1 form1) ...) expr1 expr2 ...)essential special form
Binds the vars to fresh locations holding undefined values,
evaluates the forms in the resulting environment (in some
unspecified order), assigns to each var the result of the
corresponding form, evaluates the exprs sequentially in the
resulting environment, and returns the value of the last expr.
Each binding of a var has the entire letrec expression as its
region, making it possible to define mutually recursive
procedures. See let.
(letrec ((x 2)
(y 3))
(letrec ((foo (lambda (z)
(+ x y z)))
(x 7))
(foo 4))) --> 14
(letrec ((even? (lambda (n)
(if (zero? n)
#!true
(odd? (-1+ n)))))
(odd? (lambda (n)
(if (zero? n)
#!false
(even? (-1+ n))))))
(even? 88))
--> #!true
One restriction on letrec is very important: it must be possible
to evaluate each form without referring to the value of a var.
If this restriction is violated, then the effect is undefined,
and an error may be signalled during evaluation of the forms.
The restriction is necessary because Scheme uses call by value
rather than call by name. In the most common uses of letrec,
all the forms are lambda expressions and the restriction is
satisfied automatically.
(rec var expr) special form
Equivalent to (letrec ((var expr)) var). rec is useful for
defining self-recursive procedures.
(named-lambda (name var1 ...) expr ...) special form
Equivalent to
(rec name (lambda (var1 ...) expr ...))
Rationale: Some implementatations may find it easier to provide
good debugging information when named-lambda is used instead of
rec.
(define var expr) essential special form
When typed at top level (so that it is not nested within any
other expression), this form has essentially the same effect as
(set! var expr) if var is bound. If var is not bound, however,
then the define form will bind var before performing the
assignment, whereas it would be an error to perform a set! on an
unbound identifier. The value returned by a define form is not
specified.
(define add3 (lambda (x) (+ x 3))) --> unspecified
(add3 3) --> 6
(define first car) --> unspecified
(first '(1 2)) --> 1
The semantics just described is essential. Some implementations
also allow define expressions to appear at the beginning of the
body of a lambda, named-lambda, let, let*, or letrec expression.
Such expressions are known as internal definitions as opposed to
the top level definitions described above. The variable defined
by an internal definition is local to the body of the lambda,
named-lambda, let, let*, or letrec expression. That is, var is
bound rather than assigned, and the region set up by the binding
is the entire body of the lambda, named-lambda, let, let*, or
letrec expression. For example,
(let ((x 5))
(define foo
(lambda (y)
(bar x y)))
(define bar
(lambda (a b)
(+ (* a b) a)))
(foo (+ x 3))) --> 45
Internal definitions can always be converted into an equivalent
letrec expression. For example, the let expression in the above
example is equivalent to
(let ((x 5))
(letrec ((foo (lambda (y)
(bar x y)))
(bar (lambda (a b)
(+ (* a b) a))))
(foo (+ x 3))))
(define (var0 var1 ...) expr1 expr2 ...) special form
(define (form var1 ...) expr1 expr2 ...) special form
The first form, where var0 is an identifier, is equivalent to
(define var0 (rec var0 (lambda (var1 ...) expr1 expr2 ...))).
The second form, where form is a list, is sometimes convenient
for defining a procedure that returns another procedure as its
result. It is equivalent to
(define form (lambda (var1 ...) expr1 expr2 ...)).
(define! var expr) special form
If var is bound, then the define! form is equivalent to the
corresponding set!. If var is unbound, however, define! binds
var in the global environment before performing the assignment.
Rationale: This makes sense only for implementations with a
distinguished global environment.
(defrec! var expr) special form
Equivalent to (define! var (rec var expr)).
(set! var expr) essential special form
Stores the value of expr in the location to which var is bound.
expr is evaluated but var is not. The result of the set!
expression is unspecified.
(set! x 4) --> unspecified
(1+ x) --> 5
Rationale: set! expressions are Scheme's assignment statements.
Assignment statements are seldom used in good Scheme code.
Their major uses are to initialize variables accessed
interactively and to construct objects with local state.
(begin expr1 expr2 ...) essential special form
Evaluates the exprs sequentially from left to right and returns
the value of the last expr. Used to sequence side effects such
as input and output.
(begin (set! x 5)
(1+ x)) --> 6
Also
(begin (display "4 plus 1 equals ")
(display (1+ 4)))
prints
4 plus 1 equals 5
A number of special forms such as lambda and letrec implicitly
treat their bodies as begin expressions.
(sequence expr1 expr2 ...) special form
sequence is synonymous with begin.
Rationale: sequence was used in the Abelson and Sussman text,
but it should not be used in new code.
(do ((var1 init1 step1) ...) special form
(test expr1 ...)
stmt1 ...)
The do special form is an extremely general albeit complex
iteration macro. Each var must be an identifier and each init
and step must be expressions. The init expressions are
evaluated (in some unspecified order), the vars are bound to
fresh locations, the results of the init expressions are stored
in the bindings of the vars, and then the iteration phase
begins.
Each iteration begins by evaluating test; if the result is false
(see section II.2), then the stmts are evaluated in order for
effect, the steps are evaluated (in some unspecified order), the
results of the step expressions are stored in the bindings of
the vars, and the next iteration begins.
If test evaluates true, then the exprs are evaluated from left
to right and the value of the last expr is returned as the value
of the do expression. If no exprs are present, then the value
of the do expression is unspecified.
The region set up by the binding of a var consists of the entire
do expression except for the inits.
A step may be omitted, in which case the corresponding var is
not updated. When the step is omitted the init may be omitted
as well, in which case the initial value is not specified.
(do ((vec (make-vector 5))
(i 0 (1+ i)))
((=? i 5) vec)
(vector-set! vec i i)) --> #(0 1 2 3 4)
(let ((x '(1 3 5 7 9)))
(do ((x x (cdr x))
(sum 0 (+ sum (car x))))
((null? x) sum))) --> 25
The do special form is essentially the same as the do macro in
Common Lisp. The main difference is that in Scheme the
identifier return is not bound; programmers that want to bind
return as in Common Lisp must do so explicitly (see
call-with-current-continuation).
`pattern macro special form
The backquote special form is useful for constructing a list
structure when most but not all of the desired structure is
known in advance. If no commas appear within the pattern, the
result of evaluating `pattern is equivalent (in the sense of
equal?) to the result of evaluating 'pattern. If a comma
appears within the pattern, however, the expression following
the comma is evaluated and its result is inserted into the
structure instead of the comma and the expression. If a comma
appears followed immediately by an at-sign (@), then the
following expression must evaluate to a list; the opening and
closing parentheses of the list are then "stripped away" and the
elements of the list are inserted in place of the
comma/at-sign/expression sequence.
`(a ,(+ 1 2) ,@(mapcar 1+ '(4 5 6)) b) --> (a 3 5 6 7 b)
`(((foo ,(- 10 3)) ,@(cdr '(c)) cons)) --> (((foo 7) cons))
Scheme does not have any standard facility for defining new
special forms.
Rationale: The ability to define new special forms creates
numerous problems. All current implementations of Scheme have
macro facilities that solve those problems to one degree or
another, but the solutions are quite different and it isn't
clear at this time which solution is best, or indeed whether any
of the solutions are truly adequate. Rather than standardize,
we are encouraging implementations to continue to experiment
with different solutions.
The main problems with traditional macros are: They must be
defined to the system before any code using them is loaded; this
is a common source of obscure bugs. They are usually global;
macros can be made to follow lexical scope rules as in Common
Lisp's macrolet, but many people find the resulting scope rules
confusing. Unless they are written very carefully, macros are
vulnerable to inadvertant capture of free variables; to get
around this, for example, macros may have to generate code in
which procedure values appear as quoted constants. There is a
similar problem with keywords if the keywords of special forms
are not reserved. If keywords are reserved, then either macros
introduce new reserved words, invalidating old code, or else
special forms defined by the programmer do not have the same
status as special forms defined by the system.
!II.2. Booleans
The standard boolean objects for truth and falsity are written
as #!true and #!false. What really matters, though, are the
objects that the Scheme conditional expressions (if, cond, and,
or, do) will treat as though they were true or false. The
phrase "a true value" (or sometimes just "true") means any
object treated as true by the conditional expressions, and the
phrase "a false value" (or "false") means any object treated as
false by the conditional expressions.
Of all the standard Scheme values, only #!false and the empty
list count as false in conditional expressions. #!true, pairs
(and therefore lists), symbols, numbers, strings, vectors, and
procedures all count as true.
The empty list counts as false for historical reasons only, and
programs should not rely on this because future versions of
Scheme will probably do away with this nonsense.
Programmers accustomed to other dialects of Lisp should beware
that Scheme has already done away with the nonsense that
identifies the empty list with the symbol nil.
#!false essential constant
#!false is the boolean value for falsity. The #!false object is
self-evaluating. That is, it does not need to be quoted in
programs.
'#!false --> #!false
#!false --> #!false
#!true essential constant
#!true is the boolean value for truth. The #!true object is
self-evaluating, and does not need to be quoted in programs.
(not obj) essential procedure
Returns #!true if obj is false and returns #!false otherwise.
nil variable
t variable
As a crutch for programmers accustomed to other dialects of
Lisp, some implementations provide variables nil and t whose
initial values are #!false and #!true respectively. These
variables should not be used in new code.
!II.3. Equivalence predicates
A predicate is a procedure that always returns #!true or
#!false. Of the equivalence predicates described in this
section, eq? is the most discriminating while equal? is the most
liberal. eqv? is very slightly less discriminating than eq?.
(eq? obj1 obj2) essential procedure
Returns #!true if obj1 is identical in all respects to obj2,
otherwise returns #!false. If there is any way at all that a
∂19-Mar-85 0505 @MIT-MC:forwarder@CSNET-SH.ARPA Message a011267 LONG message - part 2
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 19 Mar 85 05:04:57 PST
Received: from CSNET-SH by MIT-MC.ARPA; 19 MAR 85 07:56:39 EST
To: scheme@MIT-MC.ARPA
Subject: Message a011267 LONG message - part 2
Reply-to: cic@CSNET-SH.ARPA
Date: 19 Mar 85 07:51:18 EST (Tue)
From: "Charlotte D. Mooers" <postmaster@CSNET-SH.ARPA>
user can distinguish obj1 and obj2, then eq? will return
#!false. On the other hand, it is guaranteed that objects
maintain their identity despite being fetched from or stored
into variables or data structures.
The notion of identity used by eq? is stronger than the notions
of equivalence used by the eqv? and equal? predicates. The
constants #!true and #!false are identical to themselves and are
different from everything else, except that in some
implementations the empty list is identical to #!false for
historical reasons. Two symbols are identical if they print the
same way (except that some implementations may have "uninterned
symbols" that violate this rule). For structured objects such
as pairs and vectors the notion of sameness is defined in terms
of the primitive mutation procedures defined on those objects.
For example, two pairs are the same if and only if a set-car!
operation on one changes the car field of the other. The rules
for identity of numbers are extremely implementation-dependent
and should not be relied on.
Generally speaking, the equal? procedure should be used to
compare lists, vectors, and arrays. The string-equal? procedure
should be used to compare strings, and the =? procedure should
be used to compare numbers. The eqv? procedure is just like eq?
except that it is more inclined to say that two numbers are the
same.
(eq? 'a 'a) --> #!true
(eq? 'a 'b) --> #!false
(eq? '(a) '(a)) --> unspecified
(eq? "a" "a") --> unspecified
(eq? 2 2) --> unspecified
(eq? (cons 'a 'b) (cons 'a 'b)) --> #!false
(let ((x (read)))
(eq? (cdr (cons 'b x)) x))) --> #!true
(eqv? obj1 obj2) essential procedure
eqv? is just like eq? except that if obj1 and obj2 are exact
numbers then eqv? is guaranteed to return #!true if obj1 and
obj2 are equal according to the =? procedure.
(eq? 100000 100000) --> unspecified
(eqv? 100000 100000) --> #!true
See section II.6 for a discussion of exact numbers.
(equal? obj1 obj2) essential procedure
Returns #!true if obj1 and obj2 are identical objects or if they
are equivalent numbers, lists, strings, vectors, or arrays. Two
objects are generally considered equivalent if they print the
same. equal? may not terminate if its arguments are circular
data structures.
(equal? 'a 'a) --> #!true
(equal? '(a) '(a)) --> #!true
(equal? '(a (b) c) '(a (b) c)) --> #!true
(equal? "abc" "abc") --> #!true
(equal? 2 2) --> #!true
(equal? (make-vector 5 'a)
(make-vector 5 'a)) --> #!true
equal? is a blunderbuss of a predicate and should not be used
when a less liberal or more specific predicate will suffice.
!II.4. Pairs and lists
Lists are Lisp's -- and therefore Scheme's -- characteristic
data structures. Even Lisp and Scheme programs are lists.
The empty list is a special object that is written as an opening
parenthesis followed by a closing parenthesis:
()
The empty list has no elements, and its length is zero. The
empty list is not a pair.
Larger lists are built out of pairs. A pair (sometimes called a
"dotted pair") is a record structure with two fields called the
car and cdr fields (for historical reasons). Pairs are created
by the constructor procedure cons. The car and cdr fields are
accessed by the selector procedures car and cdr. The car and
cdr fields are assigned by the mutator procedures set-car! and
set-cdr!.
The most general notation used for Scheme pairs is the "dotted"
notation (c1 . c2) where c1 is the value of the car field and
c2 is the value of the cdr field. For example
(4 . 5)
is a pair whose car is 4 and whose cdr is 5.
The dotted notation is not often used, because more streamlined
notations exist for the common case where the cdr is the empty
list or a pair. (c1 . ()) is usually written as (c1). (c1 .
(c2 . c3)) is usually written as (c1 c2 . c3). Usually these
special notations permit a structure to be written without any
dotted pair notation at all. For example
(a . (b . (c . (d . (e . ())))))
would normally be written as
(a b c d e)
When all the dots can be made to disappear as in the example
above, the entire structure is called a proper list. Proper
lists are so common that when people speak of a list, they
usually mean a proper list. For those who prefer an inductive
definition:
1. The empty list is a proper list.
2. If l is a proper list, then any pair whose cdr is
l is also a proper list.
3. There are no other proper lists.
A proper list is therefore either the empty list or a pair from
which the empty list can be obtained by applying the cdr
procedure a finite number of times.
Whether a given pair is a proper list depends upon what is
stored in the cdr field. When the set-cdr! procedure is used,
an object can be a proper list one moment and not the next:
(define x '(a b c)) --> x
(define y x) --> y
(set-cdr! x 4) --> unspecified
x --> (a . 4)
(eq? x y) --> #!true
y --> (a . 4)
A pair object, on the other hand, will always be a pair object.
It is often convenient to speak of a homogeneous (proper) list
of objects of some particular data type, as for example (1 2 3)
is a list of integers. To be more precise, suppose D is some
data type. (Any predicate defines a data type consisting of
those objects of which the predicate is true.) Then
1. The empty list is a list of D.
2. If l is a list of D, then any pair
whose cdr is l and whose car satisfies the data
type D is also a list of D.
3. There are no other lists of D.
(pair? obj) essential procedure
Returns #!true if obj is a pair, otherwise returns #!false.
(pair? '(a . b)) --> #!true
(pair? '(a b c)) --> #!true
(pair? '()) --> #!false
(pair? '#(a b)) --> #!false
(cons obj1 obj2) essential procedure
Returns a newly allocated pair whose car is obj1 and whose cdr
is obj2. The pair is guaranteed to be different (in the sense
of eq?) from every existing object.
(cons 'a '()) --> (a)
(cons '(a) '(b c d)) --> ((a) b c d)
(cons "a" '(b c)) --> ("a" b c)
(cons 'a 3) --> (a . 3)
(cons '(a b) 'c) --> ((a b) . c)
(car pair) essential procedure
Returns the contents of the car field of pair. pair must be a
pair. Note that taking the car of the empty list is an error.
(car '(a b c)) --> a
(car '((a) b c d)) --> (a)
(car '(1 . 2)) --> 1
(car '()) --> error
(cdr pair) essential procedure
Returns the contents of the cdr field of pair. pair must be a
pair. Note that taking the cdr of the empty list is an error.
(cdr '((a) b c d)) --> (b c d)
(cdr '(1 . 2)) --> 2
(cdr '()) --> error
(set-car! pair obj) essential procedure
Stores obj in the car field of pair. pair must be a pair. The
value returned by set-car! is unspecified. This procedure can
be very confusing if used indiscriminately.
(set-cdr! pair obj) essential procedure
Stores obj in the cdr field of pair. pair must be a pair. The
value returned by set-cdr! is unspecified. This procedure can
be very confusing if used indiscriminately.
(caar pair) essential procedure
(cadr pair) essential procedure
(cdar pair) essential procedure
(cddr pair) essential procedure
(caaar pair) essential procedure
(caadr pair) essential procedure
(cadar pair) essential procedure
(caddr pair) essential procedure
(cdaar pair) essential procedure
(cdadr pair) essential procedure
(cddar pair) essential procedure
(cdddr pair) essential procedure
(caaaar pair) essential procedure
(caaadr pair) essential procedure
(caadar pair) essential procedure
(caaddr pair) essential procedure
(cadaar pair) essential procedure
(cadadr pair) essential procedure
(caddar pair) essential procedure
(cadddr pair) essential procedure
(cdaaar pair) essential procedure
(cdaadr pair) essential procedure
(cdadar pair) essential procedure
(cdaddr pair) essential procedure
(cddaar pair) essential procedure
(cddadr pair) essential procedure
(cdddar pair) essential procedure
(cddddr pair) essential procedure
These procedures are compositions of car and cdr, where for
example caddr could be defined by
(define caddr (lambda (x) (car (cdr (cdr x)))))
'() essential constant
#!null constant
() is the empty list. The #!null notation does not have to be
quoted in programs. The '() notation must include the quote,
however, because otherwise it would be a procedure call without
a procedure expression.
Rationale: Because many current Scheme interpreters deal with
expressions as list structures rather than as character strings,
they will treat an unquoted () as though it were quoted. It is
entirely possible, however, that some implementations of Scheme
will be able to detect this error.
(null? obj) essential procedure
Returns #!true if obj is the empty list, otherwise returns
#!false.
(list obj1 ...) essential procedure
Returns a list of its arguments.
(list 'a (+ 3 4) 'c) --> (a 7 c)
(length plist) essential procedure
Returns the length of plist, which must be a proper list.
(length '()) --> 0
(length '(a b c)) --> 3
(length '(a (b) (c d e))) --> 3
(append plist1 plist2) essential procedure
(append plist ...) procedure
Returns a list consisting of the elements of the first plist
followed by the elements of the other plists. All plists should
be proper lists.
(append '(x) '(y)) --> (x y)
(append '(a) '(b c d)) --> (a b c d)
(append '(a (b)) '((c))) --> (a (b) (c))
(append! plist ...) procedure
Like append but may side effect its arguments.
(reverse plist) procedure
Returns a list consisting of the elements of plist in reverse
order. plist must be a proper list.
(reverse '(a b c)) --> (c b a)
(reverse '(a (b c) d (e (f)))) --> ((e (f)) d (b c) a)
(list-ref x n) procedure
Returns the car of (list-tail x n).
(list-tail x n) procedure
Returns the sublist of x obtained by omitting the first n
elements. Could be defined by
(define list-tail
(lambda (x n)
(if (zero? n)
x
(list-tail (cdr x) (- n 1)))))
(last-pair x) procedure
Returns the last pair in the nonempty list x. Could be defined
by
(define last-pair
(lambda (x)
(if (pair? (cdr x))
(last-pair (cdr x))
x)))
(memq obj plist) essential procedure
(memv obj plist) essential procedure
(member obj plist) essential procedure
Finds the first occurrence of obj in the proper list plist and
returns the first sublist of plist beginning with obj. If obj
does not occur in plist, returns #!false. memq uses eq? to
compare obj with the elements of plist, while memv uses eqv? and
member uses equal?.
(memq 'a '(a b c)) --> (a b c)
(memq 'b '(a b c)) --> (b c)
(memq 'a '(b c d)) --> #!false
(memq (list 'a) '(b (a) c)) --> #!false
(memq 101 '(100 101 102)) --> unspecified
(memv 101 '(100 101 102)) --> (101 102)
(member (list 'a) '(b (a) c)) --> ((a) c)
(assq obj alist) essential procedure
(assv obj alist) essential procedure
(assoc obj alist) essential procedure
alist must be a proper list of pairs. Finds the first pair in
alist whose car field is obj and returns that pair. If no pair
in alist has obj as its car, returns #!false. assq uses eq? to
compare obj with the car fields of the pairs in alist, while
assv uses eqv? and assoc uses equal?.
(assq 'a '((a 1) (b 2) (c 3))) --> (a 1)
(assq 'b '((a 1) (b 2) (c 3))) --> (b 2)
(assq 'd '((a 1) (b 2) (c 3))) --> #!false
(assq '(a) '(((a)) ((b)) ((c)))) --> #!false
(assq 5 '((2 3) (5 7) (11 13))) --> unspecified
(assv 5 '((2 3) (5 7) (11 13))) --> (5 7)
(assoc '(a) '(((a)) ((b)) ((c)))) --> ((a))
Rationale: memq, memv, member, assq, assv, assoc do not have
question marks in their names because they return useful values
rather than just #!true.
!II.5. Symbols
Symbols are objects whose usefulness rests entirely on the fact
that two symbols are identical (in the sense of eq?) if and only
if their names are spelled the same way. This is exactly the
property that is needed for identifiers in programs, and so most
implementations of Scheme use them internally for that purpose.
Programmers may also use symbols as they use enumerated types in
Pascal.
The rules for writing a symbol are the same as the rules for
writing an identifier (see section I.2). As with identifiers,
different implementations of Scheme use slightly different
rules, but it is always the case that a sequence of characters
that contains no special characters and begins with a character
that cannot begin a number is taken to be a symbol; in addition
+, -, 1+, and -1+ are symbols.
The case in which a symbol is written in unimportant. Some
implementations of Scheme convert any upper case letters to
lower case, and others convert lower case to upper case.
It is guaranteed that any symbol that has been read using the
read procedure and subsequently written out using the write
procedure will read back in as the identical symbol (in the
sense of eq?). The string->symbol procedure, however, can
create symbols for which the write/read invariance may not hold
because their names contain special characters or letters in the
non-standard case.
Rationale: Some implementations of Lisp have a feature known as
"slashification" in order to guarantee write/read invariance for
all symbols, but historically the most important use of this
feature has been to compensate for the lack of a string data
type. Some implementations have "uninterned symbols", which
defeat write/read invariance even in implementations with
slashification and also generate exceptions to the rule that two
symbols are the same if and only if their names are spelled the
same. It is questionable whether these features are worth their
complexity, so they are not standard in Scheme.
(symbol? obj) essential procedure
Returns #!true is obj is a symbol, otherwise returns #!false.
(symbol? 'foo) --> #!true
(symbol? (car '(a b))) --> #!true
(symbol? "bar") --> #!false
(symbol->string symbol) essential procedure
Returns the name of symbol as a string. symbol->string performs
no case conversion. See string->symbol. The following examples
assume the read procedure converts to lower case:
(symbol->string 'flying-fish) --> "flying-fish"
(symbol->string 'Martin) --> "martin"
(symbol->string
(string->symbol "Malvina")) --> "Malvina"
(string->symbol string) essential procedure
Returns the symbol whose name is string. string->symbol can
create symbols with special symbols or upper case letters in
their names, but it is usually a bad idea to create such symbols
because in some implementations of Scheme they cannot be read as
themselves. See symbol->string.
'mISSISSIppi --> mississippi
(string->symbol "mISSISSIppi") --> mISSISSIppi
(eq? 'bitBlt
(string->symbol "bitBlt")) --> #!false
(eq? 'JollyWog
(string->symbol
(symbol->string 'JollyWog))) --> #!true
(string-equal?
"K. Harper, M.D."
(symbol->string
(string->symbol
"K. Harper, M.D."))) --> #!true
!II.6. Numbers (part 1)
Numerical computation has traditionally been neglected by the
Lisp community. Until Common Lisp there has been no carefully
thought out strategy for organizing numerical computation, and
with the exception of the MacLisp system there has been little
effort to execute numerical code efficiently. We applaud the
excellent work of the Common Lisp committee and we accept many
of their recommendations. In some ways we simplify and
generalize their proposals in a manner consistent with the
purposes of Scheme.
Scheme's numerical operations treat numbers as abstract data, as
independent of the machine representation as is possible. Thus,
the casual user should be able to write simple programs without
having to know that the implementation may use fixed-point,
floating-point, and perhaps other representations for his data.
Unfortunately, this illusion of uniformity can only be sustained
approximately -- the implementation of numbers will leak out of
our abstraction whenever the user must be in control of
precision, or accuracy, or when he must construct especially
efficient computations. Thus we also must provide escape
mechanisms so that a sophisticated programmer can exercise more
control of the execution of his code and the representation of
his data when it is essential to do so.
We separate out several apparently related issues of
representation -- the abstract numbers, their machine
representation, and the input/output formats of the symbolic
expressions which denote numerical constants. We will use
mathematical words such as NUMBER, COMPLEX, REAL, RATIONAL, and
INTEGER for properties of the abstract numbers, data-structure
names such as FIXNUM, BIGNUM, RATNUM, and FLONUM for machine
representations, and names like INT, FIX, FLO, SCI, RAT, POLAR,
and RECT for input/output formats.
Notations for numbers are the subject of section II.7.
Numbers.
A Scheme system provides data of type NUMBER, which is the most
general numerical type supported by that system. NUMBER is
likely to be a complicated union type implemented in terms of
FIXNUMs, BIGNUMS, FLONUMS, etc. but this should not be apparent
to a naive user. What the user sees is that the obvious
operations on numbers produce the mathematically expected
results, within the limits of the implementation. Thus if the
user divides 3 by 2, he should get something like 1.5 (or, the
exact fraction 3/2). If he adds that result to itself, and if
the implementation can swing it, he should get an exact 3.
Mathematically, numbers may be arranged into a tower of subtypes
with natural projections and injections relating adjacent
members of the tower:
NUMBER
COMPLEX
REAL
RATIONAL
INTEGER
We impose a uniform rule of downward coercion -- a number of one
type is also of a lower type if the injection (up) of the
projection (down) of a number leaves the number unchanged.
Since this tower is a real mathematical entity, Scheme provides
predicates and procedures that access the tower.
Not all Scheme implementations must provide the whole tower, but
they are required to implement a coherent subset, consistent
with the purposes of Scheme.
Exactness.
Numbers are either EXACT or INEXACT. A number is exact if it
was derived from EXACT numbers using only EXACT operations. A
number is INEXACT if it models a quantity known only
approximately, if it was derived using INEXACT ingredients, or
if it was derived using INEXACT operations. Thus INEXACTness is
a contagious property of a number. Some operations, such as the
square root (of non-square numbers) must be INEXACT because of
the finite precision of our representations. Other operations
are inexact because of implementation requirements. We
emphasize that exactness is independent of the position of the
number on the tower. It is perfectly possible to have an
INEXACT INTEGER or an EXACT REAL; 355/113 may be an EXACT
RATIONAL or it may be an INEXACT RATIONAL approximation to pi,
depending on the application.
Operationally, it is the system's responsibility to combine
EXACT numbers using exact methods, such as infinite precision
integer and rational arithmetic, where possible. An
implementation may not be able to do this (if it does not use
infinite precision integers and rationals), but if a number
becomes inexact for implementation reasons there is probably an
important error condition, such as integer overflow, to be
reported. Arithmetic on INEXACT numbers is not so constrained.
The system may use floating point and other flaky representation
strategies for INEXACT numbers. This is not to say that
implementors need not use the best known algorithms for INEXACT
computations -- only that high-quality approximate methods are
allowed. In a system which cannot explicitly distinguish exact
from inexact numbers the system must do its best to maintain
precision. Scheme systems must not burden users with numerical
operations described in terms of hardware and operating-system
dependent representations such as FIXNUM and FLONUM. These
representation issues should not be germane to the user's
problems.
We highly recommend that the IEEE 32-bit and 64-bit
floating-point standards be adopted for implementations that use
floating-point internal representations. To minimize loss of
precision we adopt the following rules: If an implementation
uses several different sizes of floating-point formats, the
results of any operation with a floating-point result must be
expressed in the largest format used to express any of the
floating-point arguments to that operation. It is desirable
(but not required) for potentially irrational operations such as
sqrt, when applied to EXACT arguments, to produce EXACT answers
when that is possible (eg. sqrt[4]=2, exactly). If an EXACT
number (or an INEXACT number represented as a FIXNUM, a BIGNUM,
or a RATNUM) is operated upon so as to produce an INEXACT result
(as by sqrt), and if the result is represented as a FLONUM, then
the largest available format FLONUM must be used; but if the
result is expressed as a RATNUM then the rational approximation
must have at least as much precision as the largest available
format FLONUM. (Note that this last rule is much stronger than
that used in Common Lisp. Consider the result of the square
root of a rational, for example.)
Numerical operations.
Scheme provides the usual set of operations for manipulating
numbers. In general, numerical operations require numerical
arguments. For succintness we let the following meta-symbols
range over the indicated types of object in our descriptions,
and we let these meta-symbols specify the types of the arguments
to numeric operations. It is an error for an operation to be
presented with an argument that it is not specified to handle.
obj any arbitrary object
z, z1, ... zi, ... complex, real, rational, integer
x, x1, ... xi, ... real, rational, integer
q, q1, ... qi, ... rational, integer
n, n1, ... ni, ... integer
(number? obj) essential procedure
(complex? obj) essential procedure
(real? obj) essential procedure
(rational? obj) essential procedure
(integer? obj) essential procedure
These numerical type predicates can be applied to any kind of
argument. They return true if the object is of the named type.
In general, if a type predicate is true of a number then all
higher type predicates are also true of that number. Not every
system supports all of these types; it is entirely possible to
have a Scheme system that has only INTEGERs. Nonetheless every
implementation of Scheme must have all of these predicates.
(zero? z) essential procedure
(positive? x) essential procedure
(negative? x) essential procedure
(odd? n) essential procedure
(even? n) essential procedure
(exact? z) essential procedure
(inexact? z) essential procedure
These numerical predicates test a number for a particular
property. They return a boolean value.
(= z1 z2) essential procedure
(=? z1 z2) essential procedure
(= z1 z2 z3 ...) procedure
(=? z1 z2 z3 ...) procedure
(< x1 x2) essential procedure
(<? x1 x2) essential procedure
(< x1 x2 x3 ...) procedure
(<? x1 x2 x3 ...) procedure
(> x1 x2) essential procedure
(>? x1 x2) essential procedure
(> x1 x2 x3 ...) procedure
(>? x1 x2 x3 ...) procedure
(<= x1 x2) essential procedure
(<=? x1 x2) essential procedure
(<= x1 x2 x3 ...) procedure
(<=? x1 x2 x3 ...) procedure
(>= x1 x2) essential procedure
(>=? x1 x2) essential procedure
(>= x1 x2 x3 ...) procedure
(>=? x1 x2 x3 ...) procedure
The numerical comparison predicates have redundant names (with
and without the terminal "?") to make all populations happy.
They optionally take many arguments, as in Common Lisp, to
facilitate range checks. These procedures return true if their
arguments are (respectively): numerically equal, monotonically
increasing, monotonically decreasing, monotonically
nondecreasing, or monotonically nonincreasing. Warning: On
INEXACT numbers equality tests will give unreliable results;
other numerical comparisons are only heuristically useful (ask a
numerical analyst about this!).
(max x1 x2) essential procedure
(max x1 x2 ...) procedure
(min x1 x2) essential procedure
(min x1 x2 ...) procedure
Returns the maximum or minimum of its arguments, respectively.
(+ z1 z2) essential procedure
(+ z1 ...) procedure
(* z1 z2) essential procedure
(* z1 ...) procedure
These procedures return the sum or product of their arguments.
(+ 3 4) --> 7
(+ 3) --> 3
(+) --> 0
(* 4) --> 4
(*) --> 1
(- z1 z2) essential procedure
(- z1 z2 ...) procedure
(/ z1 z2) essential procedure
(/ z1 z2 ...) procedure
With two or more arguments, these procedures return the
difference or (complex) quotient of their arguments, associating
to the left. With one argument, however, they return the
additive or multiplicative inverse of their argument.
(- 3 4) --> -1
(- 3 4 5) --> -6
(- 3) --> -3
(/ 3 4 5) --> 3/20
(/ 3) --> 1/3
(1+ z) procedure
(-1+ z) procedure
These procedures return the result of adding or subtracting 1 to
their argument.
(abs z) essential procedure
Returns the magnitude of its argument.
(abs -7) --> 7
(abs -3+4i) --> 5
(quotient n1 n2) essential procedure
(remainder n1 n2) essential procedure
(modulo n1 n2) procedure
In general, these are intended to implement number-theoretic
(integer) division, where for positive integers n1 and n2 if n3
and n4 are integers such that
n1 = n3 * n2 + n4 and 0 <= n4 < n2
then
(quotient n1 n2) --> n3
(remainder n1 n2) --> n4
(modulo n1 n2) --> n4
remainder and modulo differ on negative arguments as do the
Common Lisp rem and mod procedures -- the remainder always has
the sign of the dividend, the modulo always has the sign of the
divisor:
(modulo 13 4) --> 1
(remainder 13 4) --> 1
(modulo -13 4) --> 3
(remainder -13 4) --> -1
(modulo 13 -4) --> -3
(remainder 13 -4) --> 1
(modulo -13 -4) --> -1
(remainder -13 -4) --> -1
(gcd n1 ...) procedure
(lcm n1 ...) procedure
These procedures return the greatest common divisor or least
common multiple of their arguments. The arguments to lcm should
be nonzero. The result is always non-negative.
(gcd 32 -36) --> 4
(gcd) --> 0
(lcm 32 -36) --> 288
(lcm) --> 1
(floor x) procedure
(ceiling x) procedure
(truncate x) procedure
(round x) procedure
(rationalize x y) procedure
(rationalize x) procedure
These procedures create integers and rationals. Their results
are not EXACT -- in fact, their results are clearly INEXACT,
though they can be made EXACT with an explicit exactness
coercion.
floor returns the largest integer not larger than x. ceiling
returns the smallest integer not smaller than x. truncate
returns the integer of maximal absolute value not larger than x.
round returns the closest integer to x, rounding to even when x
is halfway between two integers. With two arguments,
rationalize produces the best rational approximation to x within
the tolerance specified by y. With one argument, rationalize
produces the best rational approximation to x, preserving all of
the precision in its representation.
(exp z) procedure
(log z) procedure
(expt z1 z2) procedure
(sqrt z) procedure
(sin z) procedure
(cos z) procedure
(tan z) procedure
(asin z) procedure
(acos z) procedure
(atan z1 z2) procedure
These procedures are part of every implementation that supports
real numbers. Their meanings conform with the Common Lisp
standard. (Be careful of the branch cuts if complex numbers are
allowed.)
(make-rectangular x1 x2) procedure
(make-polar x3 x4) procedure
(real-part z) procedure
(imag-part z) procedure
(magnitude z) procedure
(angle z) procedure
These procedures are part of every implementation that supports
complex numbers. Suppose x1, x2, x3, and x4 are real numbers
and z is a complex number such that
z = x1 + x2 i = x3 * e ↑ (x4 i)
Then make-rectangular and make-polar return z, real-part returns
x1, imag-part returns x2, magnitude returns x3, and angle
returns x4.
(exact->inexact z) procedure
(inexact->exact z) procedure
exact->inexact returns an inexact representation of z, which is
a pretty harmless thing to do. inexact->exact returns an exact
representation of z; be sure you know what you are doing here!
!II.7. Numbers (part 2)
Numerical Input and Output.
Scheme allows all of the traditional ways of expressing
numerical constants, though any particular implementation may
support only some of them. These expressions are intended to be
purely notational; any kind of number may be expressed in any
form that the user deems convenient. Of course, expressing 1/7
as a limited-precision decimal fraction will not exactly express
the number, but this approximate expression may be just what the
user wants to see.
The expressions of numerical constants can be specified using
formats. The system provides a procedure, number->string, which
takes a number and a format and which produces a string which is
the printed expression of the given number in the given format.
(number->string number format) procedure
This procedure will mostly be used by sophisticated users and in
system programs. In general, a naive user will need to know
nothing about the formats because the system printer will have
reasonable default formats for all types of NUMBERs. The system
reader will construct reasonable default numerical types for
numbers expressed in each of the formats it recognizes. If a
user needs control of the coercion from strings to numbers he
will use string->number, which takes a string, an exactness, and
a radix and which produces a number of the maximally precise
applicable type expressed by the given string.
(string->number string exactness radix) procedure
The exactness is a symbol, either E (for EXACT) or I (for
INEXACT). The radix is also a symbol: B for binary, O for
octal, D for decimal, and X for hexadecimal. Returns a number
parsed from the string.
Formats may have parameters. For example, the (SCI 5 2) format
specifies that a number is to be expressed in Fortran scientific
format with 5 significant places and two places after the radix
point.
The following are all numerical constant expressions. The
comment shows the format that was used to produce the
expression:
123 +123 -123 ; (INT)
12345678901234567890123456789 ; A big one!
355/113 -355/113 +355/113 ; (RAT)
+123.45 -123.45 ; (FIX 2)
3.14159265358979 ; (FIX 14)
3.14159265358979 ; (FLO 15)
123.450 ; (FLO 6)
-123.45E-1 ; (SCI 5 2)
123E3 123E-3 -123E-3 ; (SCI 3 0)
-1+2i ; (RECT (INT) (INT))
1.2@1.570796 ; (POLAR (FIX 1) (FLO 7))
A numerical constant may be specified with an explicit radix by
a prefix. The prefixes are: #B (binary), #O (octal), #D
(decimal), #X (hex). A format may specify that a number be
expressed in a particular radix. The radix prefix may be
suppressed. For example, one may express a complex number in
polar form with the magnitude in octal and the angle in decimal
as follows:
#o1.2@#d1.570796327 ; (POLAR (FLO 2 (RADIX O)) (FLO (RADIX D)))
#o1.2@1.570796327 ; (POLAR (FLO 2 (RADIX O)) (FLO (RADIX D S))
A numerical constant may be specified to be either EXACT or
INEXACT by a prefix. The prefixes are: #I (inexact), #E
(exact). An exactness prefix may appear before or after any
radix prefix that is used. A format may specify that a number
be expressed with an explicit exactness prefix, or it may force
the exactness to be suppressed. For example, the following are
ways to output an inexact value for pi:
#I355/113 ; (RAT (EXACTNESS))
355/113 ; (RAT (EXACTNESS S))
#I3.1416 ; (FIX 4 (EXACTNESS))
An attempt to produce more digits than are available in the
internal machine representation of a number will be marked with
a "#" filling the extra digits. This is not a statement that
the implementation knows or keeps track of the significance of a
number, just that the machine will flag attempts to produce 20
digits of a number which has only 15 digits of machine
representation:
3.14158265358979##### ; (FLO 20 (EXACTNESS S))
In systems with both single and double precision FLONUMs one may
want to specify which size we want to use to internally
represent a constant. For example, we may want a constant that
is pi rounded to the single precision length, or we might want a
long number which has the value 6/10. In either case, we are
specifying an explicit way to represent an INEXACT number. For
this purpose, we allow one to express a number with a prefix
which indicates short or long FLONUM representation:
#S3.14159265358979 ; Round to short -- 3.141593
#L.6 ; Extend to long -- .600000000000000
Details of formats.
The format of a number is notated as a list beginning with a
format descriptor, such as SCI. Following the descriptor are
parameters used by that descriptor, such as the number of
significant digits to be used. Parameters which are omitted are
defaulted. Next, one may specify modifiers, such as RADIX or
EXACTNESS, which themselves may be parameterized. The format
descriptors are:
(INT)
Express as an integer. The radix point is implicit. If there are
not enough significant places, as in trying to express 6.0238E23
(internally represented as a 7 digit FLONUM) as an integer we would
get "6023800################".
(RAT n)
Express as a rational fraction. n specifies the largest
denominator to be used in constructing a rational approximation to
the number being expressed. If n is omitted it defaults to
infinity.
(FIX n)
Express with a fixed radix point. n specifies the number of
places to the right of the radix point. n defaults to the size of a
single-precision FLONUM. If there are not enough significant
places, as in trying to express 6.0238E23 (internally represented
as a 7 digit FLONUM) as a (FIX 2) we would get
"6023800################.##".
(FLO n)
Express with a floating radix point. n specifies the total number
of places to be displayed. n defaults to the size of a single-
precision FLONUM. If the number is out of range, it is converted
to (SCI). (FLO H) allows the system to heuristically express a FLO
for human consumption (as in the MacLisp printer).
(SCI n m)
Express in exponential notation. n specifies the total number of
places to be displayed. n defaults to the size of a single-
precision FLONUM. m specifies the number of places to the right of
the radix point. m defaults to n-1. (SCI H) does heuristic
expression.
(RECT r i)
Express as a rectangular form complex number. r and i are formats
for the real and imaginary parts respectively. They default to
∂19-Mar-85 0515 @MIT-MC:forwarder@CSNET-SH.ARPA Message a011267 LONG message - part 3
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 19 Mar 85 05:15:11 PST
Received: from CSNET-SH by MIT-MC.ARPA; 19 MAR 85 08:07:47 EST
To: scheme@MIT-MC.ARPA
Subject: Message a011267 LONG message - part 3
Reply-to: cic@CSNET-SH.ARPA
Date: 19 Mar 85 07:53:34 EST (Tue)
From: "Charlotte D. Mooers" <postmaster@CSNET-SH.ARPA>
(HEUR).
(POLAR m a)
Express as a polar form complex number. m and a are formats for
the magnitude and angle respectively. m and a default to (HEUR).
(HEUR)
Express heuristically, as in the MacLisp printer (see Steele),
using the minimum number of digits required to get an expression
which when coerced back to a number produces the original machine
representation. EXACT numbers are expressed as (INT) or (RAT).
INEXACT numbers are expressed as (FLO H) or (SCI H) depending on
their range. Complex numbers are expressed in (RECT). This is the
normal default of the system printer.
The following modifiers may be added to a numerical format
specification:
(EXACTNESS s)
This controls the expression of the exactness label of a number. s
indicates whether the exactness is to be E (expressed) or S
(suppressed). s defaults to E. If no exactness modifier is
specified for a format the exactness is by default not expressed.
(RADIX r s)
This forces a number to be expressed in the radix r. r may be B
(binary), O (octal), D (decimal), or X (hex). s indicates whether
the radix label is to be E (expressed) or S (suppressed). s
defaults to E. If no radix modifier is specified the default is
decimal and the label is suppressed.
! II.8. Strings
Strings are written as sequences of characters enclosed within
doublequotes ("). A doublequote can be written inside a string
only by escaping it with a backslash (\), as in
"The word \"Recursion\" has many different meanings."
A backslash can be written inside a string only by escaping it
with another backslash. Scheme does not specify the effect of a
backslash within a string that is not followed by either a
doublequote or another backslash.
A string may continue from one line to the next, but this is
usually a bad idea because the exact effect varies from one
computer system to another.
Several of the string procedures involve characters or lists of
characters. Characters are written using the #\ notation of
Common Lisp. For example:
#a ; lower case letter
#A ; upper case letter
#( ; the left parenthesis as a character
# ; the space character
#space ; the preferred way to notate a space character
#newline ; the newline character
The #\ notation is not an essential part of Scheme, however.
Even implementations that support the #\ notation for input do
not have to support it for output, and there is no requirement
that the data type of characters be disjoint from data types
such as integers or strings.
This section defines no destructive operations on strings, but a
much larger collection of string operations including
destructive operations has been proposed by Chris Hanson and is
under consideration.
(string? obj) essential procedure
Returns #!true if obj is a string, otherwise returns #!false.
(string-equal? string1 string2) essential procedure
Returns #!true if string1 and string2 are strings of the same
length and have the same characters in the same positions.
(string-less? string1 string2) essential procedure
Returns #!true if string1 is lexicographically less than
string2. The ordering defined by string-less? varies from one
computer system to another, but it is always an irreflexive
total ordering on strings.
(string-length string) essential procedure
Returns the number of characters in string.
(string-ref string k) essential procedure
k must be a nonnegative integer less than the string-length of
string. Returns character k of string using zero-origin
addressing.
(string-ref "abcde" 2) --> #c
(string-append string1 string2) essential procedure
(string-append string ...) procedure
Returns a string whose characters form the catenation of the
given strings.
(string->list string) essential procedure
Returns a list of the characters that make up string. See
list->string.
(list->string char-list) essential procedure
char-list must be a proper list of characters. Returns a string
formed from the characters in char-list. list->string and
string->list are inverses so far as equal? is concerned.
!II.9. Vectors
Vectors are heterogenous mutable structures whose elements are
indexed by integers. The first element in a vector is indexed
by zero, and the last element is indexed by one less than the
length of the vector. A vector of length 3 containing the
number 0 in element 0, the list (2 2 2 2) in element 1, and the
string "Anna" in element 2 can be written as
#(0 (2 2 2 2) "Anna")
Vectors are created by the constructor procedure make-vector.
The elements are accessed and assigned by the procedures
vector-ref and vector-set!.
(vector? obj) essential procedure
Returns #!true if obj is a vector, otherwise returns #!false.
(make-vector size) essential procedure
(make-vector size fill) procedure
Returns a newly allocated vector of size elements. If a second
argument is given, then each element is initialized to fill.
Otherwise the initial contents of each element is unspecified.
(vector obj ...) essential procedure
Returns a newly allocated vector whose elements contain the
given arguments. Analogous to list.
(vector 'a 'b 'c) --> #(a b c)
(vector-length vec) essential procedure
Returns the number of elements in the vector vec.
(vector-ref vec k) essential procedure
Returns the contents of element k of the vector vec. k must be
a nonnegative integer less than the vector-length of vec.
(vector-ref '#(1 1 2 3 5 8 13 21) 5) --> 8
(vector-set! vec k obj) essential procedure
Stores obj in element k of the vector vec. k must be a
nonnegative integer less than the vector-length of vec. The
value returned by vector-set! is not specified.
(define vec '#(0 (2 2 2 2) "Anna")) --> vec
(vector-set! vec 1 '("Sue" "Sue")) --> unspecified
vec --> #(0
("Sue" "Sue")
"Anna")
(vector->list vec) essential procedure
Returns a list of the objects contained in the elements of vec.
See list->vector.
(vector->list '#(dah dah didah)) --> (dah dah didah)
(list->vector elts) essential procedure
Returns a newly created vector whose elements are initialized to
the elements of the proper list elts.
(list->vector '(dididit dah)) --> #(dididit dah)
(vector-fill! vec fill) procedure
Stores fill in every element of the vector vec. The value
returned by vector-fill! is not specified.
!II.10. The object table
(object-hash obj) procedure
(object-unhash n) procedure
object-hash associates an integer with obj in a global table and
returns obj. object-hash guarantees that distinct objects (in
the sense of eq?) are associated with distinct integers.
object-unhash takes an integer and returns the object associated
with that integer if there is one, returning false otherwise.
Rationale: object-hash and object-unhash can be implemented
using association lists and the assq procedure, but the intent
is that they be efficient hash functions for general objects.
!II.11. Procedures
Procedures are created when lambda expressions are evaluated.
Procedures do not have a standard printed representation because
recursively defined procedures are conceptually infinite and may
be implementationally circular.
The most common thing to do with a procedure is to call it with
zero or more arguments. A Scheme procedure may also be stored
in data structures or passed as an argument to procedures such
as those described below.
(apply proc args) essential procedure
(apply proc arg1 ... args) procedure
proc must be a procedure and args must be a proper list of
arguments. The first (essential) form calls proc with the
elements of args as the actual arguments. The second form is a
generalization of the first that calls proc with the elements of
(append (list arg1 ...) args) as the actual arguments.
(apply + (list 3 4)) --> 7
(define compose
(lambda (f g)
(lambda args
(f (apply g args))))) --> compose
((compose 1+ *) 3 4) --> 13
(mapcar f plist) essential procedure
(mapcar f plist1 plist2 ...) procedure
f must be a procedure of one argument and the plists must be
proper lists. If more than one plist is given, then the plists
should all be the same length. Applies f element-wise to the
elements of the plists and returns a list of the results. The
order in which f is applied to the elements of the plists is not
specified.
(mapcar cadr '((a b) (d e) (g h))) --> (b e h)
(mapcar (lambda (n) (expt n n))
'(1 2 3 4 5)) --> (1 4 27 256 3125)
(mapcar + '(1 2 3) '(4 5 6)) --> (5 7 9)
(define count 0) --> unspecified
(mapcar (lambda (ignored)
(set! count (1+ count))
count)
'(a b c)) --> unspecified
The mapcar procedure often goes by the name of map in other
advanced programming languages.
(mapc f plist) essential procedure
(mapc f plist1 plist2 ...) procedure
The arguments to mapc are like the arguments to mapcar, but mapc
calls f for its side effects rather than for its values. Unlike
mapcar, mapc is guaranteed to call f on the elements of the
plists in order from the first element to the last, and the
value returned by mapc is not specified.
(define v (make-vector 5)) --> v
(mapc (lambda (i)
(vector-set! v i (* i i)))
'(0 1 2 3 4)) --> unspecified
v --> #(0 1 4 9 16)
The name of mapc is traditional and cannot otherwise be
defended.
(call-with-current-continuation f) procedure
The classic use of call-with-current-continuation is for
structured, non-local exits from loops or procedure bodies, but
in fact call-with-current-continuation is extremely useful for
implementing a wide variety of advanced control structures.
Whenever a Scheme expression is evaluated there is a
continuation wanting the result of the expression. The
continuation represents an entire future for the computation.
If the expression is evaluated at top level, for example, then
the continuation will take the result, print it on the screen,
prompt for the next input, evaluate it, and so on forever. Most
of the time the continuation includes actions specified by user
code, as in a continuation that will take the result, multiply
it by the value stored in a local variable, add seven, and give
the answer to the top level continuation to be printed.
Normally these ubiquitous continuations are hidden behind the
scenes and programmers don't think much about them. On rare
occasions, however, when programmers need to do something fancy,
then they may need to deal with continuations explicitly.
call-with-current-continuation allows Scheme programmers to
create a procedure that acts just like the current continuation.
f must be a procedure of one argument.
call-with-current-continuation packages up the current
continuation as an "escape procedure" and passes it as an
argument to f. The escape procedure is an ordinary Scheme
procedure of one argument that, if it is later passed a value,
will ignore whatever continuation is in effect at that later
time and will give the value instead to the continuation that
was in effect when the escape procedure was created.
The escape procedure created by call-with-current-continuation
has unlimited extent just like any other procedure in Scheme.
It may be stored in variables or data structures and may be
called as many times as desired.
The following examples show only the most common uses of
call-with-current-continuation. If all real programs were as
simple as these examples, there would be no need for a procedure
with the power of call-with-current-continuation.
(call-with-current-continuation
(lambda (exit)
(mapc (lambda (x)
(if (negative? x)
(exit x)))
'(54 0 37 -3 245 19))
#!true)) --> -3
(define list-length
(lambda (obj)
(call-with-current-continuation
(lambda (return)
((rec loop (lambda (obj)
(cond ((null? obj) 0)
((pair? obj)
(1+ (loop (cdr obj))))
(else (return #!false)))))
obj)))))
--> list-length
(list-length '(1 2 3 4)) --> 4
(list-length '(a b . c)) --> #!false
Rationale: Most serious programming languages incorporate one or
more special purpose escape constructs with names like exit,
return, or even goto. In 1965, however, Peter Landin invented a
general purpose escape operator called the J-operator. John
Reynolds described a simpler but equally powerful construct in
1972. The catch special form described by Sussman and Steele in
the 1975 report on Scheme is exactly the same as Reynolds's
construct, though its name came from a less general construct in
MacLisp. The fact that the full power of Scheme's catch could
be obtained using a procedure rather than a special form was
noticed in 1982 by the implementors of Scheme 311, and the name
call-with-current-continuation was coined later that year. Some
people think the name is good because its length discourages
programmers from using the procedure casually; others have taken
to calling the procedure call/cc.
!II.12. Ports
Ports represent input and output devices. To Scheme, an input
device is a Scheme object that can deliver characters upon
command, while an output device is a Scheme object that can
accept characters.
(call-with-input-file string proc) essential procedure
(call-with-output-file string proc) essential procedure
proc is a procedure of one argument, and string is a string
naming a file. For call-with-input-file, the file must already
exist; for call-with-output-file, the effect is unspecified if
the file already exists. Calls proc with one argument: the port
obtained by opening the named file for input or output. If the
file cannot be opened, an error is signalled. If the procedure
returns, then the port is closed automatically and the value
yielded by the procedure is returned. If the current
continuation ever changes in such a way as to make it doubtful
that the procedure will return, the port may be closed
automatically, but the exact interaction with escape procedures
is unspecified.
Rationale: Whether or not the port is closed when the procedure
does not return is mainly a performance issue, of greatest
importance when there is a small limit on the number of files
that can be open at once. The extreme generality of Scheme's
escape procedures makes it impossible to know for certain
whether a procedure will return, and procedures can in fact
return more than once.
(input-port? obj) essential procedure
(output-port? obj) essential procedure
Returns #!true if obj is an input port or output port
(respectively), otherwise returns #!false.
(current-input-port) essential procedure
(current-output-port) essential procedure
Returns the current default input or output port.
(with-input-from-file string thunk) procedure
(with-output-to-file string thunk) procedure
thunk is a procedure of no arguments, and string is a string
naming a file. For with-input-from-file, the file must already
exist; for with-output-to-file, the effect is unspecified if the
file already exists. The file is opened for input or output, an
input or output port connected to it is made the default value
returned by current-input-port or current-output-port, and the
thunk is called with no arguments. When the thunk returns, the
port is closed and the previous default is restored.
with-input-from-file and with-output-to-file return the value
yielded by thunk. Furthermore these procedures will attempt to
close the default port and restore the previous default whenever
the current continuation changes in such a way as to make it
doubtful that the thunk will ever return. See
call-with-input-file and call-with-output-file.
(open-input-file filename) procedure
Takes a string naming an existing file and returns an input port
capable of delivering characters from the file. If the file
cannot be opened, an error is signalled.
(open-output-file filename) procedure
Takes a string naming an output file to be created and returns
an output port capable of writing characters to a new file by
that name. If the file cannot be opened, an error is signalled.
If a file with the given name already exists, the effect is
unspecified.
(close-input-port port) procedure
(close-output-port port) procedure
Closes the file associated with port, rendering the port
incapable of delivering or writing characters. The value
returned is not specified.
!II.13. Input
The read procedure converts written representations of Scheme
objects into the objects themselves. The written
representations for Scheme objects are described in the sections
devoted to the operations on those objects, and the grubby
details of lexical syntax are described in an appendix.
(eof? obj) essential procedure
Returns true iff obj is an end of file object. The precise set
of end of file objects will vary among implementations, but in
any case no end of file objects will ever be a character or an
object that can be read in using read.
(read) essential procedure
(read port) essential procedure
Returns the next object parsable from the given input port,
updating port to point to the first character past the end of
the written representation of the object. If an end of file is
encountered in the input before any characters are found that
can begin an object, then an end of file object is returned. If
an end of file is encountered after the beginning of an object's
written representation, but the written representation is
incomplete and therefore not parsable, an error is signalled.
The port argument may be omitted, in which case it defaults to
the value returned by current-input-port.
Rationale: This corresponds to Common Lisp's
read-preserving-whitespace, but for simplicity it is never an
error to encounter end of file except in the middle of an
object.
(read-char) essential procedure
(read-char port) essential procedure
Reads the next character available from the input port, updating
the port to point to the following character. If no more
characters are available, an end of file object is returned.
port may be omitted, in which case it defaults to the value
returned by current-input-port.
(listen?) procedure
(listen? port) procedure
Returns true if a character is ready on the input port so that a
read-char operation will not hang, and returns false otherwise.
If the port is at end of file then the value returned by listen?
is unspecified. port may be omitted, in which case it defaults
to the value returned by current-input-port.
(load filename) essential procedure
filename should be a string naming an existing file containing
Scheme source code. The load procedure reads expressions from
the file and evaluates them sequentially as though they had been
typed interactively. It is not specified whether the results of
the expressions are printed, however, nor is it specified
whether the load procedure affects the values returned by
current-input-stream and current-output-stream during the
loading process. load returns an unspecified value.
Rationale: For portability load must operate on source files.
Its operation on other kinds of files necessarily varies among
implementations.
!II.14. Output
(write obj) essential procedure
(write obj port) essential procedure
Writes a representation of obj to the given port. Strings that
appear in the written representation are enclosed in
doublequotes, and within those strings backslash and doublequote
characters are escaped by backslashes. write returns an
unspecified value. The port argument may be omitted, in which
case it defaults to the value returned by current-output-stream.
See display.
(display obj) essential procedure
(display obj port) essential procedure
Writes a representation of obj to the given port. Strings that
appear in the written representation are not enclosed in
doublequotes, and no characters are escaped within those
strings. display returns an unspecified value. The port
argument may be omitted, in which case it defaults to the value
returned by current-output-stream. See write.
Rationale: Like Common Lisp's prin1 and princ, write is for
producing machine-readable output and display is for producing
human-readable output. Implementations that allow
"slashification" within symbols will probably want write but not
display to slashify funny characters in symbols.
(newline) essential procedure
(newline port) essential procedure
Writes an end of line to port. Exactly how this is done differs
from one operating system to another. Returns an unspecified
value. The port argument may be omitted, in which case it
defaults to the value returned by current-output-port.
(write-char char) essential procedure
(write-char char port) essential procedure
Writes the character char (not a written representation of the
character) to the given port and returns an unspecified value.
The port argument may be omitted, in which case it defaults to
the value returned by current-output-port.
(transcript-on filename) procedure
(transcript-off) procedure
filename must be a string naming an output file to be created.
The effect of transcript-on is to open the named file for
output, and to cause a transcript of subsequent interaction
between the user and the Scheme system to be written to the
file. The transcript is ended by a call to transcript-off,
which closes the transcript file. Only one transcript may be in
progress at any time, though some implementations may relax this
restriction. The values returned by these procedures are
unspecified.
Rationale: These procedures are redundant in some systems, but
systems that need them should provide them.
!References
Harold Abelson and Gerald Jay Sussman with Julie Sussman,
Structure and Interpretation of Computer Programs, MIT Press,
1985.
William Clinger, "The Scheme 311 compiler: an exercise in
denotational semantics", Conference Record of the 1984 ACM
Symposium on Lisp and Functional Programming, August 1984, pages
356-364.
Carol Fessenden, William Clinger, Daniel P Friedman, and
Christopher Haynes, "Scheme 311 version 4 reference manual",
Indiana University Computer Science Technical Report 137,
February 1983.
D Friedman, C Haynes, E Kohlbecker, and M Wand, "Scheme 84
interim reference manual", Indiana University Computer Science
Technical Report 153, January 1985.
Christopher T Haynes, Daniel P Friedman, and Mitchell Wand,
"Continuations and coroutines", Conference Record of the 1984
ACM Symposium on Lisp and Functional Programming, August 1984,
pages 293-298.
Peter Landin, "A correspondence between Algol 60 and Church's
lambda notation: Part I", Communications of the ACM 8, 2,
February 1965, pages 89-101.
MIT Scheme Manual, Seventh Edition, September 1984.
Peter Naur et al, "Revised report on the algorithmic language
Algol 60", Communications of the ACM 6, January 1963, pages
1-17.
Kent M Pitman, The Revised MacLisp Manual, MIT Artificial
Intelligence Laboratory Technical Report 295, 21 May 1983
(Saturday Evening Edition).
Jonathan A Rees, Norman I Adams, James R Meehan, "The T manual",
Fourth Edition, 10 January 1984.
John Reynolds, "Definitional interpreters for higher order
programming languages", ACM Conference Proceedings, 1972, pages
717-740.
Guy Lewis Steele Jr and Gerald Jay Sussman, "The revised report
on Scheme, a dialect of Lisp", MIT Artificial Intelligence
Laboratory Memo 452, January 1978.
Guy L Steele, Rabbit: a compiler for Scheme, MIT Artificial
Intelligence Laboratory Technical Report 474, May 1978.
Guy L Steele, "An overview of Common Lisp", Conference Record of
the 1982 ACM Symposium on Lisp and Functional Programming,
August 1982, pages 98-107.
Guy Lewis Steele Jr, Common Lisp: the Language, Digital Press,
1984.
Gerald Jay Sussman and Guy Lewis Steele Jr, "Scheme: an
interpreter for extended lambda calculus", MIT Artificial
Intelligence Laboratory Memo 349, December 1975.
Gerald Jay Sussman, Jack Holloway, Guy L Steele, and Alan Bell,
"Scheme-79 -- Lisp on a chip", IEEE Computer 14, 7, July 1981,
pages 10-21.
∂19-Mar-85 1044 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa Keyboard inputs
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 19 Mar 85 10:44:39 PST
Received: from csnet-relay by MIT-MC.ARPA; 19 MAR 85 13:43:27 EST
Received: from indiana by csnet-relay.csnet id a008437; 19 Mar 85 13:42 EST
Date: Tue, 19 Mar 85 10:55:58 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA03087; Tue, 19 Mar 85 10:55:58 est
To: scheme@mit-mc.ARPA
Subject: Keyboard inputs
> On interactive streams users may have the possibility of
>erasing typed characters. What happens if listen? returns true and
>then the user erases the character? The program which invoked listen?
>will probably attempt to read a character thinking that it will not
>hang but it will. We had this bug and went to a fair amount of hair
>to get it fixed.
This problem doesn't arise if the rubout handler is implemented
using READ-CHAR. The system should be designed this way if you
expect to implement an Emacs-like editor in Scheme.
If the rubout handler is at a lower level than READ-CHAR, then
the system is probably set up so that the user first edits her
input using rubouts and whatever other facilities are available
(cut and paste using a mouse, Emacs, whatever). Let's say that
this input is liquid. When the user is satisfied with her input
she does something to signal that the input should be sent to
Scheme, perhaps by typing the "Execute" key (on the HP 9836) or
the "Enter" key (on the Macintosh). At that moment the input
should be frozen so that it cannot be edited further. At any
given time the input buffer for READ-CHAR may contain older
characters that are frozen as well as newer characters that are
liquid. READ-CHAR should return only frozen characters, and
should hang if there are none. The LISTEN? procedure (or whatever
we wind up calling it) should therefore return true only if there
are frozen characters in the buffer.
It is possible to design a system that can switch back and forth
between the first way and the second way. (Unix calls these raw
mode and cooked mode.)
> We have not talked at all about keyboard interrupts. It
>seems to me that any reasonable implementation should provide a
>way for the user to (at least) abort an infinite loop. It would
>be nice if we had a simple standard mechanism for doing this, but
>implementations would be free to have more keyborad interrupts
>(we currently have 5 by default). I propose that we choose some
>control character (↑G, for example) which on all implementations
>and unless inhibited (an editor may want to do this) will
>interrupt Scheme and make it return to the top-level
>read-eval-print loop.
Yes, any reasonable implementation must have keyboard interrupts,
but we shouldn't standardize on the characters. Consider Scheme
312, which runs under four very different operating systems.
Under CP/M-68k, control-G is fine as the interrupt character, and
an operating system convention leads users to expect that
control-C will leave Scheme for good (it does). Under Un*x,
however, users expect SIGINT to be the interrupt character and
SIGQUIT to be the abort character; usually these are control-C
and control-\, respectively. Under HP Pascal the HP 9836
"Execute" key is rigged to send a control-C; it doesn't make
sense for "Execute" to interrupt or abort. The Macintosh doesn't
have a control key (the command (cloverleaf) key is something
completely different); pull-down menus are probably more
appropriate. In short, no matter what conventions we could
choose, they would be wrong for some machines.
∂19-Mar-85 1445 @MIT-MC:JINX@MIT-OZ Keyboard inputs
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 19 Mar 85 14:45:37 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 19 MAR 85 17:44:34 EST
Date: 19 Mar 1985 17:44 EST (Tue)
Message-ID: <JINX.12096359061.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Will Clinger <willc%indiana.csnet@CSNET-RELAY.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: Keyboard inputs
In-reply-to: Msg of 19 Mar 1985 10:55-EST from Will Clinger <willc%indiana.csnet at csnet-relay.arpa>
I think you don't understand the problem with listen?
The system need not have a rubout handler written in Scheme to
have an Emacs-like editor. MIT-Scheme has a rubout handler written in
Pascal (almost all IO is written in Pascal), and Edwin (Chris Hanson's
editor) works perfectly fine, since it bypasses buffered IO.
We have two kinds of terminal read-char: One is used by the
reader, and is buffered (no characters are given to Scheme until some
key (Execute on HP9836, Newline on UNIX) is typed). The other is
immediate (it returns as soon as a character is typed, without waiting
for any special character). The former is much more efficient under
some operating systems, and eliminates the need for a complicated
rubout handler since the reader never needs to back out (according to
GJS, 1/4 of all the code of MacLisp at some point was the rubout
handler). Having an Emacs-like front-end is not incompatible with
this, since the front-end need not give any characters to Scheme until
no further character-level processing is needed.
It is inconvenient, however, to do all input in this mode (I'd
hate to have to type a newline after a single character command to a
debugger, for example). This is why we have immediate read-char also,
which is the default. Users can type asynchronously, and frequently
do so ahead of the system. For consistency, the user should be able
to edit (especially rub-out) his typeahead until it is read. Since
the system does not know whether the next read-char will be immediate
or not, it cannot lock the required characters unless it locks all,
clearly unpalatable.
The problem with listen? arises, for example, from programs
which ask for confirmation or a simple choice but assume a default if
no input becomes available in some period of time. Assume that the
user types a character, the program invokes listen? which returns
true, and the user then deletes the character before the program has
had a chance to invoke immediate read-char. This is quite likely on a
timesharing system, where the user may delete while Scheme is not the
current process running. Clearly the program will hang while it
should not (it was intended that it "time-out"). Clearly listen? is
wothless unless it applies to both liquid and frozen characters
(otherwise a terminator would have to be typed after the option,
ugh!). The problem is trivially solved if listen? locks the
character.
I believe that this problem can arise even if there is no
buffered io in a system. On Lisp systems that I know (including
MacLisp and Lisp Machines), rubout-handling is built into read, not
into tyi, and therefore user programs that use tyi rather than read do
not (by default) allow users to rub-out their input. If you allow
rub-out on read-char throughout the system (which is certainly
desirable), the problem potentially exists.
Since adding this extra constraint to the definition of
listen? solves all these bugs and allows implementors of the
io system greater freedom, I think it should be added.
On my previous message I advocated for eliminating listen? in
favor of non-hanging-read-char, but I drop this. Chris Hanson has
pointed out that unless untyi were provided, this would be the cause
of pretty ugly code.
∂19-Mar-85 2228 @MIT-MC:CPH@MIT-OZ Revisions to String Proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 19 Mar 85 22:28:35 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 20 MAR 85 01:24:39 EST
Date: Wed, 20 Mar 1985 01:24 EST
Message-ID: <CPH.12096442797.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Scheme@MIT-MC
Subject: Revisions to String Proposal
I have revised the earlier proposal I submitted for String operations.
The revision was somewhat of a hatchet job, but I think that the
important functionality remains.
What follows is some notes referring to the earlier proposal. After
that I have written a small bit of commentary about mutation of
strings.
!
----------------------------------------------------------------------
Characters
The basic operations on characters are the following; they should be
essential.
(CHAR? <object>)
True iff <object> is a character.
(CHAR->INTEGER <char>)
(INTEGER->CHAR <integer>)
Maps to coerce characters to integers and vice versa. If two
characters have a certain relationship in the character ordering,
then the corresponding integers must have the same relationship in
the integer ordering. (If I recall right, this means these maps
are order isomorphisms between characters and integers.)
I would like to propose that the following be essential. These are
the case sensitive order predicates for characters; they define the
character ordering. I think that the Common Lisp restrictions as to
the ordering should be adopted.
The names have been changed to conform with Common Lisp, after Don
Oxley pointed out that CHAR-EQUAL? was case sensitive, and in CL
CHAR-EQUAL was the case insensitive version. I hope that this will
clear things up a bit.
Each of the following accepts two character objects, and compares them
in the obvious way. Optionally, they may take more arguments, as do
the corresponding numeric predicates.
CHAR=? CHAR<? CHAR<=? CHAR>? CHAR>=?
The following should be optional; they are the case insensitive
versions of the above.
CHAR-CI=? CHAR-CI<? CHAR-CI<=? CHAR-CI>? CHAR-CI>=?
These character class predicates should be optional, with the meaning
described in the Common Lisp manual. They each take one argument,
which must be a character.
CHAR-UPPER-CASE?
CHAR-LOWER-CASE?
CHAR-ALPHABETIC?
CHAR-NUMERIC?
CHAR-ALPHANUMERIC?
CHAR-WHITESPACE?
CHAR-GRAPHIC?
The following should be optional; each takes a character object and
returns another character object. They perform case conversion if the
argument is lower or upper case, respectively.
CHAR-UPCASE
CHAR-DOWNCASE
!
----------------------------------------------------------------------
Strings
I think that the following should be essential, as described in my
earlier proposal:
STRING? MAKE-STRING STRING-LENGTH STRING-REF STRING->LIST
LIST->STRING SUBSTRING STRING-APPEND STRING-NULL?
Similarly to the transformation for characters, the following should
be essential for two arguments, and optionally should take more.
STRING=? STRING<? STRING<=? STRING>? STRING>=?
Again, these case insensitive versions are optional.
STRING-CI=? STRING-CI<? STRING-CI<=? STRING-CI>? STRING-CI>=?
Next, these optional procedures provide a small set of operations for
mutable strings.
STRING-ALLOCATE STRING-COPY STRING-SET! SUBSTRING-FILL!
SUBSTRING-MOVE-RIGHT! SUBSTRING-MOVE-LEFT!
The remaining operations, while useful, are probably not important
enough to standardize on. As I have already demonstrated, all of them
can be implemented given the above operations.
Here is the corrected text for the -MOVE- operations:
(SUBSTRING-MOVE-RIGHT! STRING1 START1 END1 STRING2 START2)
(SUBSTRING-MOVE-LEFT! STRING1 START1 END1 STRING2 START2)
These operations destructively copy the substring <STRING1, START1,
END1> to the string STRING2 starting at the index START2. It must be
the case that <STRING2, START2, (+ START2 (- END1 START1))> is a
substring; this latter substring is destructively modified to contain
the contents of the former substring.
The operations differ only when the two substrings overlap, i.e. when
STRING1 and STRING2 are EQ? and the index sets of the substrings are
not disjoint. In this case, the operations are defined to copy the
elements of the first substring serially. SUBSTRING-MOVE-RIGHT!
copies the first substring starting with the rightmost element,
proceeding to the left, while SUBSTRING-MOVE-LEFT! starts with the
leftmost element, proceeding to the right. This has the effect that
the two operations can be used to shift groups of characters right or
left, respectively, within a given string.
!
----------------------------------------------------------------------
Mutation
I have tried to be careful about the issue of mutable strings. None
of the operations which I have proposed as "essential" mutate strings.
I have provided a small set of operations, marked as "optional", which
DO mutate strings. I believe that mutation of strings is basically
reasonable; although I understand that in some very important cases,
in particular the names of interned symbols, there should be some
guarantee that a string cannot be mutated. I believe that this can be
solved by one of these simple methods:
1. A string could have an internal bit which, when set, would prevent
mutation.
2. There could be two types of strings. In this case, it would be
reasonable to decide that the read/print syntax for mutable strings
need not be the same as for non-mutable strings.
Anyway, I have chosen to have all strings be mutable in the MIT
implementation, because that is the simplest choice providing the most
power. To the best of my knowledge, no one has ever been screwed by
this decision, and it seems unlikely that anyone ever would.
∂20-Mar-85 1254 JAR@MIT-MC Ports and streams
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 20 Mar 85 12:54:44 PST
Date: 20 March 1985 15:54-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: Ports and streams
To: SCHEME @ MIT-MC
I think that we generally agree that were it not for performance
reasons, we would have only streams (in the FP/A&S sense), and not
ports; am I correct? E.g., a stream object would need to be consed for
each character read from or written to a file; this would mean frequent
GC's if a lot of file I/O was happening. It's unfortunate that our
design is driven by considerations like this, but I guess that's how
things are.
So the I/O primitives in the essential dialect manipulate things called
ports, which are positions on streams of characters. The two notions
are equivalent (ports could be defined if the only primitives were stream
primitives, and vice versa), so people who care about writing code
which does I/O in a pure style can still do so, by implementing
I/O streams in terms of I/O ports themselves.
So far so good. This message is about terminology, not semantics. I
think that "port" is a bad term. The real-life usage of the term "port"
(door or harbor) doesn't seem to be a good fit with that of the word
"stream". I guess the image that's intended is of a door, with the
program on one side and a stream of things on the other, and the things
coming into the program's awareness or control through the door. Or
perhaps the stream flows through the door? Streams flow under bridges,
maybe, or through channels (I don't like "channel" because it has
incompatible connotations in computer science), or into aqueducts or
over waterfalls, but through doors? The other meaning of "port"
doesn't make sense: rivers or possibly streams might flow into harbors
or ports, but that's not what makes a port a port; a port is someplace
where ships dock, load, etc. So "port" is a very strange word to use in
connection with streams.
A different metaphor is that a "port" is a sort of a cursor or a marker
which moves along a sequence (stream). Well, what moves up and down a
sequence or stream? Here are some transportation metaphors:
line, screen cursor
conduit vehicle
rail train
road car
river boat
stream raft
How about "raft"? A raft might be an appropriate vehicle for a stream.
I guess this is pretty cutesy, but it's an idea. One argument in favor
is that "raft" doesn't have connotations in computer science like many
other words (port, channel) do. Also, the metaphor is obscure enough
that no one would need to know how silly it is; users could imagine that
RAFT is an acronym, or some technical term derived from some obscure
branch of mathematics or semantics, or whatever. Sounds sort of like
"rack" or "rail," terms that certain language designers use without
embarrassment. And it's short, a distinct advantage.
These two metaphors reflect the difference between a stream and a
streambed. If you want to see everything which floats by on a stream,
it's sufficient to sit one place (e.g. on a bridge, or on a bank, or at
its outlet) and relax and enjoy the view. "Stream" here is the stuff
that is flowing. If, however, you want to see all the places that the
stream goes, you have to get on a raft or boat or just wade the entire
length of the thing from source to outlet. This "stream" is a
geographical thing, something you'd find on a map.
Besides the fact that "port" is a mixed (or at least poor) metaphor, I
am opposed to the term because it reminds me of Franz Lisp. I'd rather
not be reminded of Franz every time I use Scheme.
I know this is pretty random, but I just wanted to voice my unhappiness
and get people thinking about more appropriate terms.
Jonathan
∂20-Mar-85 1542 @MIT-MC:KMP@SCRC-STONY-BROOK Ports and streams
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 20 Mar 85 15:42:09 PST
Received: from SCRC-STONY-BROOK by MIT-MC via Chaosnet; 20 MAR 85 18:36:30 EST
Received: from SCRC-RIO-DE-JANEIRO by SCRC-STONY-BROOK via CHAOS with CHAOS-MAIL id 200687; Wed 20-Mar-85 17:11:04-EST
Date: Wed, 20 Mar 85 17:11 EST
From: Kent M Pitman <KMP@SCRC-STONY-BROOK.ARPA>
Subject: Ports and streams
To: Scheme@MIT-MC.ARPA
cc: JAR@MIT-MC.ARPA
In-Reply-To: The message of 20 Mar 85 15:54-EST from Jonathan A Rees <JAR at MIT-MC>
Message-ID: <850320171127.2.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM>
Date: 20 March 1985 15:54-EST
From: Jonathan A Rees <JAR @ MIT-MC>
... A different metaphor is that a "port" is a sort of a cursor or a
marker which moves along a sequence (stream). Well, what moves up
and down a sequence or stream? How about "raft"? ...
I also dislike "port" for much the same reasons as Jonathan presented.
I support the proposal for the new term "raft".
∂21-Mar-85 1448 @MIT-MC:linus!ramsdell@mitre-bedford MAPC and MAPCAR
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Mar 85 14:46:23 PST
Received: from mitre-bedford by MIT-MC.ARPA; 21 MAR 85 17:46:38 EST
Date: 21 Mar 1985 17:35:15-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA18613; Thu, 21 Mar 85 09:30:14 est
Date: Thu, 21 Mar 85 09:30:14 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503211430.AA18613@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: MAPC and MAPCAR
I mildly support the change from "port" to "raft", but
GREATLY support changes in other SCHEME names. In particular,
I find the terms MAPC and MAPCAR offensive. Why not use the
names WALK and MAP as is done in T?
I like the idea of using english words as names. Thus I prefer
LABELS to LETREC. Given that some names will not be english,
at the very least, word parts can be separated with dash.
LETREC => LET-REC
DEFREC => DEF-REC
NEWLINE => NEW-LINE
As you can guess, CAR and CDR are losers in my book. How about:
CAR => -<-
CDR => ->-
CADR => -<>-
CDAR => -><-
CxxxR => -xxx- with "A" substituted by "<" and "D" substituted by ">".
Bold and wonderful changes from traditional Lisps are being suggested by
the Scheme document, for example, dumping the confusion between the
empty list and logical false. Now is no time to get stuck with
traditional name.
John
∂21-Mar-85 1449 @MIT-MC:linus!ramsdell@mitre-bedford Re: DRAFT of the Revised Revised Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Mar 85 14:48:42 PST
Received: from mitre-bedford by MIT-MC.ARPA; 21 MAR 85 17:47:31 EST
Date: 21 Mar 1985 17:35:34-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA21592; Thu, 21 Mar 85 13:35:25 est
Date: Thu, 21 Mar 85 13:35:25 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503211835.AA21592@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: Re: DRAFT of the Revised Revised Report
A few comments:
1) How about consolidating descriptions of all procedures
that convert things to a string. E.g. symbol->string
should be described in the same section as number->string.
Part II: A catalog of Scheme
II.5 Symbols
II.6 Numbers
II.7 Vectors
II.8 Strings
II.9 String conversions. <-!
II.10 The object table
II.11 Procedures
II.12 Ports
II.13 Input
II.14 Output
2) When I use a one arm if, I am usually writting side effects,
but with a two arm if, I am not. I suggest these two different
uses be glorified with different names. In particular, let's
name the one arm if "when".
(if condition consequent alternative) essential special form
(when condition expr1 expr2 ...) essential special form
The result of the when is undefined.
3) Since define has two syntaxes, how about giving rec or
named-lambda the same two. You could drop one of the
special forms as a result.
(named-lambda (name var1 ...) expr ...) special form
(named-lambda name expr ...) special form
4) I think it is great that the value of set! is undefined.
5) What happened to iterate? I use it much more than I use do.
It would be nice to name it loop, but I'm sure the T people would
object.
6) Macro not defined in the begining of the report.
v
`pattern macro special form
7) It is excellent that there is an attempt to stop confusing
the empty list with boolean false.
8) The phrase "more inclined to..." does not sound like the kind
of words one should use in a description of eqv?.
be used to compare numbers. The eqv? procedure is just like eq?
except that it is more inclined to say that two numbers are the
same.
9) Missing predicate: list?.
(list? obj) essential procedure
(define (list? l) (or (pair? l) (null? l)))
10) I was happy to find that property lists are not part of the
definition of symbols.
11) I vote for the long name instead of call/cc.
(call-with-current-continuation f) procedure
John
∂21-Mar-85 1554 @MIT-MC:JINX@MIT-OZ DRAFT of the Revised Revised Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Mar 85 15:51:13 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 21 MAR 85 18:51:21 EST
Date: 21 Mar 1985 18:49 EST (Thu)
Message-ID: <JINX.12096895077.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: scheme@MIT-MC
Subject: DRAFT of the Revised Revised Report
In-reply-to: Msg of 21 Mar 1985 17:35-EST
Thu 21 Mar 85 13:35:25 est from linus!ramsdell at Mitre-Bedford,
linus!ramsdell (John D. Ramsdell) at Mitre-Bedford
0) I agree that car, cdr, etc, are poor names, yet I have not
seen good alternatives to them except first and rest, which don't nest
(a la c....r) too well. I think that their use is so entrenched that
it would be hard to get used to other things.
Random related comment: A possibility we have not considered
is general-car-cdr:
(general-car-cdr #b1 l) = l
(general-car-cdr #b10 l) = (car l)
(general-car-cdr #b11 l) = (cdr l)
(general-car-cdr #b101 l) = (cadr l)
(general-car-cdr #b110 l) = (cdar l)
etc.
Thus c....r = (lambda (l) (general-car-cdr n l))
Where n = #b1**** with the mapping a->0 b->1
C...r (except car and cdr) are defined like that in MIT
Scheme. Note that general-car-cdr is not limited to a length of 4 for
the chain of car-cdrs, and is trivial to implement.
2 & 5) The reason for not having a different name for the one-armed
IF is that we tried very hard to keep the number of special forms to a
minimum. Since they are easily distinguished by the number of
subforms, there is no need to add another. Note that the same
philosophy leads MIT to have named LET, which is exactly (except for
the name) what ITERATE used to be.
3) I don't think that the syntax (named-lambda name expr) is a
good idea as a substitute for rec. An extension of rec would allow
something like (rec a-circular-list (cons 'a a-circular-list)) where
there are no lambdas, so named-lambda is inappropriate.
Note that both rec and named-lambda are optional, so there is
no need to drop any. Different dialects have preferences for one
over the other, so an arbitrary decision would probably not sit well.
Note also that MIT Scheme allows also the syntax
(named-lambda ((foo . args1) . args2) . body) =
(named-lambda (foo . args1) (lambda args2 . body))
which is not on the report.
9) I don't think that the list? you propose is missing. I think
list? should be defined as
(define (list? l)
(or (null? l) (and (pair? l) (list? (cdr l)))))
, in other words, proper-list?.
What you define as list? is what we (MIT-Scheme) call
weak-list? which we have never found a real use for.
I would like to eliminate the confusion about lists. I
propose that list refer to proper lists, and anything else built out
of pairs be called a pair-graph. Thus lists are pair-graphs but not
viceversa. The procedure LIST produces a list, and the procedure
LIST? tests whether an object is one.
∂22-Mar-85 0951 JAR@MIT-MC (if a b)
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Mar 85 09:50:58 PST
Date: 22 March 1985 12:51-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: (if a b)
To: SCHEME @ MIT-MC
In-reply-to: Msg of 21 Mar 1985 17:35:34-EST
Thu 21 Mar 85 13:35:25 est from linus!ramsdell at Mitre-Bedford,
linus!ramsdell (John D. Ramsdell) at Mitre-Bedford
I'm in agreement with John Ramsdell in opposing amputated IF (although I
also agree with Bill Rozas that WHEN is a bad idea). IF-forms should
always have two arms. Could someone explain to me again why it is a
good idea? It complicates the language. You can always use (COND (test
...)) if you really don't want to write another arm. And your dialect
can optionally include the amputated variant. I don't see how one can
simultaneously support (IF A B) and oppose (DEFINE (FOO X) Y).
Jonathan
∂22-Mar-85 1322 @MIT-MC:BARTLEY%ti-csl.csnet@csnet-relay.arpa ASSERT, ports, and NIL
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Mar 85 13:22:07 PST
Received: from csnet-relay by MIT-MC.ARPA; 22 MAR 85 16:22:23 EST
Received: from ti-csl by csnet-relay.csnet id ac00183; 22 Mar 85 14:11 EST
Date: 22 Mar 1985 1032-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: ASSERT, ports, and NIL
To: Scheme@mit-mc.ARPA
cc: Bartley%ti-csl.csnet@csnet-relay.arpa
Received: from csl60 by ti-csl; Fri, 22 Mar 85 10:56 CST
I have some miscellaneous comments on topics raised recently...
1. I like Will's ASSERT. I have used the same approach before in
compilers for Pascal and other languages and find that it is quite
appropriate for both the programmer and a dataflow-oriented optimizer.
2. I like PORT. My Webster's includes the following definitions:
(2a) an opening for intake or exhaust of a fluid ...
(2c) a place of access to a system
This is close enough to the concept we have in mind. Frankly, "raft" seems
too whimsical for a language that deserves to be taken seriously.
3. I hate NIL. However, I have a problem of great practical significance
to our work that I'd like help with. As much as I abhor it personally,
Common Lisp equates the empty list, the logical <false> value, and the
symbol NIL. Here at TI's Computer Science Lab, we are building
experimental multi-lingual program development environments for various
machines (including our Explorer Lisp machine) in which Scheme, Common
Lisp, Prolog, and other languages need to co-exist. I see no practical way
to avoid defining our Scheme's #!NULL and #!FALSE as anything other than
the symbol NIL. Otherwise the two languages cannot share list data. If
anyone has a good general solution to this problem, I'd like to hear of it.
If not, I ask that this interpretation be permitted by the revised report.
Surely we aren't the only ones interested in multi-lingual issues?
Regards,
David Bartley
-------
∂22-Mar-85 1325 @MIT-MC:BARTLEY%ti-csl.csnet@csnet-relay.arpa Re: Revisions to String Proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Mar 85 13:25:35 PST
Received: from csnet-relay by MIT-MC.ARPA; 22 MAR 85 16:22:54 EST
Received: from ti-csl by csnet-relay.csnet id ag00183; 22 Mar 85 14:13 EST
Date: 22 Mar 1985 1105-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: Re: Revisions to String Proposal
To: CPH%MIT-OZ@mit-mc.ARPA, Scheme@mit-mc.ARPA
cc: Bartley%ti-csl.csnet@csnet-relay.arpa
In-Reply-To: Your message of 20-Mar-85 0242-CST
Received: from csl60 by ti-csl; Fri, 22 Mar 85 12:26 CST
I am quite pleased with Chris' revised string proposal.
A minor suggestion -- perhaps the = and < comparators could be made
essential and the <=, >, and >= comparators made optional.
Regards,
David Bartley
-------
∂22-Mar-85 1344 @MIT-MC:GJS@MIT-OZ Re: ASSERT, ports, and NIL
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Mar 85 13:44:42 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 22 MAR 85 16:44:32 EST
Date: Fri 22 Mar 85 16:43:08-EST
From: Gerald Jay Sussman <GJS%MIT-OZ@MIT-MC.ARPA>
Subject: Re: ASSERT, ports, and NIL
To: Bartley%ti-csl.csnet@CSNET-RELAY.ARPA
cc: scheme@MIT-MC
In-Reply-To: Message from "David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>" of Fri 22 Mar 85 11:32:00-EST
I like "port" too!
-------
∂22-Mar-85 1353 JAR@MIT-MC NIL
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Mar 85 13:53:38 PST
Date: 22 March 1985 16:52-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: NIL
To: Bartley%ti-csl.csnet @ CSNET-RELAY
cc: SCHEME @ MIT-MC
In-reply-to: Msg of 22 Mar 1985 1032-CST from David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
Date: 22 Mar 1985 1032-CST
From: David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
3. I hate NIL. However, I have a problem of great practical significance
to our work that I'd like help with. As much as I abhor it personally,
Common Lisp equates the empty list, the logical <false> value, and the
symbol NIL. Here at TI's Computer Science Lab, we are building
experimental multi-lingual program development environments for various
machines (including our Explorer Lisp machine) in which Scheme, Common
Lisp, Prolog, and other languages need to co-exist. I see no practical way
to avoid defining our Scheme's #!NULL and #!FALSE as anything other than
the symbol NIL. Otherwise the two languages cannot share list data. If
anyone has a good general solution to this problem, I'd like to hear of it.
If not, I ask that this interpretation be permitted by the revised report.
Surely we aren't the only ones interested in multi-lingual issues?
I don't think we need to or should allow either false or the empty list
to be a symbol. In our PDP-10 Maclisp prototype of T, we solved the
inconsistency by doing (REMOB 'NIL). Maclisp had a symbol NIL, which
was the same as false and the empty list, and T had a symbol NIL
(created, after the REMOB happened, the first time that READ encountered
the sequence "NIL"), which was different from the Maclisp symbol NIL. T
and Maclisp coexisted happily. Then we did:
(defun symbol? (x)
(and x (symbolp x)))
Similarly, in the Common Lisp emulation package in T, we created a
parameter to READ which caused the atom NIL to read in as the empty
list, using the same framework that allows atoms like 1E3 and 5/8 to be
read as numbers instead of symbols. Then, we emulated Common Lisp
symbols as the union of T symbols and the empty list:
(define (symbolp x)
(or (symbol? x) (null? x)))
(define (intern x)
(if (string-equal? x "NIL") ;(no packages)
'()
(string->symbol x)))
(define (symbol-name x)
(xcond ((symbol? x) (symbol->string x))
((null? x) "NIL")))
and so on.
So Common Lisp (with its own environment, syntax table, and read table
distinct from T's) coexisted happily with T.
The much harder problem is emulating the status quo when false and the
empty list are distinguished, but let's not talk about that.
Jonathan
∂22-Mar-85 1835 @MIT-MC:HUDAK@YALE.ARPA Re: DRAFT of the Revised Revised Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Mar 85 18:34:52 PST
Received: from yale by MIT-MC.ARPA; 22 MAR 85 21:21:48 EST
Received: by YALE-BULLDOG.YALE.ARPA; 21 Mar 85 21:31:50 EST (Thu)
Message-Id: <8503220231.AA28348@YALE-BULLDOG.YALE.ARPA>
Received: from YALE-RING by YALE-RES via CHAOS; Thu, 21 Mar 85 21:28:34 EST
Subject: Re: DRAFT of the Revised Revised Report
Date: Thu, 21 Mar 85 21:28:35 EST
From: Paul Hudak <Hudak@YALE.ARPA>
To: Bill Rozas <JINX%MIT-OZ@MIT-MC>
Cc: scheme@MIT-MC
In-Reply-To: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>, 21 Mar 1985 18:49 EST (Thu)
0) I agree that car, cdr, etc, are poor names, yet I have not
seen good alternatives to them except first and rest, which don't
nest (a la c....r) too well. I think that their use is so
entrenched that it would be hard to get used to other things.
Another possibility is head and tail. Both of them actually *do*
nest fairly well; for example, according to the following scheme:
car&cdr head&tail first&rest
----------------------------------
caar hhd fft
cadr htl frt
cdar thd rft
cddr ttl rrt
caaar hhhd ffft
caadr hhtl ffrt
cadar hthd frft
caddr httl frrt
... ... ...
My personal preference is head and tail, but anything is better than
car and cdr.
-Paul
∂22-Mar-85 2049 @MIT-MC:ANDY@SU-SCORE.ARPA Re: DRAFT of the Revised Revised Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Mar 85 20:48:54 PST
Received: from SU-SCORE.ARPA by MIT-MC.ARPA; 22 MAR 85 23:49:16 EST
Date: Fri 22 Mar 85 20:47:41-PST
From: Andy Freeman <ANDY@SU-SCORE.ARPA>
Subject: Re: DRAFT of the Revised Revised Report
To: Hudak@YALE.ARPA
cc: JINX%MIT-OZ@MIT-MC.ARPA, scheme@MIT-MC.ARPA
In-Reply-To: Message from "Paul Hudak <Hudak@YALE.ARPA>" of Fri 22 Mar 85 18:36:19-PST
Actually I prefer car/cdr over head/tail and first/rest because the
former have no outside associations (I've never seen a 7094) and the
latter do. I then define more appropriate names that reflect the
meaning in the program. More meaningful (or less ugly) names don't
encourage this. (I'm not sure about -<>-, etc., but they share the
unnecessary topological connotations of head/tail and first/rest.)
Then again, I don't want my cons operations to suggest that I'm
working on lists, just cons'. (Someone has already mentioned the
difference between cons? and list?) Also, car/cdr are nice harmless
bit of history.
-andy
-------
∂24-Mar-85 0007 @MIT-MC:CPH@MIT-OZ
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 24 Mar 85 00:07:05 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 24 MAR 85 03:06:34 EST
Date: Sun, 24 Mar 1985 02:26 EST
Message-ID: <CPH.12097502667.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Hudak@YALE.ARPA, Jinx%MIT-OZ@MIT-MC.ARPA
Cc: Scheme@MIT-MC
In-reply-to: Msg of 21 Mar 1985 21:28-EST from Paul Hudak <Hudak at YALE.ARPA>
Maybe I'm just being old and tired, but I like CAR and CDR! I would
be saddened to see them lost in a wave of "modernization". Would you
consider changing LAMBDA to something else? I think that CAR, CDR and
CONS have the same historical value (as does COND, I suppose).
Obviously, I like keeping in touch with the past, as long as it
doesn't cloud the thinking of the future. This doesn't seem to be
such a case; might as well call the operations "0" and "1", if you
want to be really, really efficient.
∂24-Mar-85 0009 @MIT-MC:CPH@MIT-OZ Revisions to String Proposal
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 24 Mar 85 00:09:24 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 24 MAR 85 03:06:38 EST
Date: Sun, 24 Mar 1985 02:37 EST
Message-ID: <CPH.12097504585.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: David Bartley <Bartley%ti-csl.csnet@CSNET-RELAY.ARPA>
Cc: Scheme@MIT-MC.ARPA
Subject: Revisions to String Proposal
In-reply-to: Msg of 22 Mar 1985 12:05-EST from David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
Date: Friday, 22 March 1985 12:05-EST
From: David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
A minor suggestion -- perhaps the = and < comparators could be made
essential and the <=, >, and >= comparators made optional.
I think that this is quite reasonable -- often I try to code this way.
Although... is the cost of tying up these few identifiers worth the
extra expressive power they may bring? I think it probably is;
sometimes it seems that one wants to say "(>= ...)" rather than "(not
(< ...))". The extra symbols will be bound in people's minds whether
or not they are in the "revised revised report" or not.
∂25-Mar-85 1306 @MIT-MC:BARTLEY%ti-csl.csnet@csnet-relay.arpa Re: NIL
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 25 Mar 85 13:06:14 PST
Received: from csnet-relay by MIT-MC.ARPA; 25 MAR 85 15:44:44 EST
Received: from ti-csl by csnet-relay.csnet id ae10480; 25 Mar 85 15:34 EST
Date: 25 Mar 1985 1153-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: Re: NIL
To: JAR@mit-mc.ARPA, Bartley%ti-csl.csnet@csnet-relay.arpa
cc: SCHEME@mit-mc.ARPA, Bartley%ti-csl.csnet@csnet-relay.arpa
In-Reply-To: Your message of 22-Mar-85 1552-CST
Received: from csl60 by ti-csl; Mon, 25 Mar 85 13:41 CST
Re: Jonathon's suggestion for rationalizing NIL in Common Lisp and () in
Scheme...
When Common Lisp is implemented on top of Scheme, or at the same time as
Scheme, your second approach is quite workable. It relies on making the
representation of the empty list suit Scheme's needs and patching up a few
components of Common Lisp so () "looks" like the symbol NIL. My only
concern here is that I'd like to use the same reader, the same SYMBOL?/
SYMBOLP routine, etc., but I'm willing to give in on those.
The first example you gave, bringing up Scheme (T) on top of Common Lisp
(Maclisp), still has a problem. If Scheme is introduced into a system in
which the idea that NIL=='NIL=='() is deeply ingrained (e.g. in microcode),
then I see no way to allow a user to jump back and forth between processes
written in the two languages and which must share the same list data,
without making 'NIL=='().
I intend to make new systems conform along the lines you suggest. However,
I still would like a multi-lingual implementation built on an existing Lisp
system to be allowed by the standard.
Regards,
David Bartley
-------
∂25-Mar-85 1443 @MIT-MC:linus!ramsdell@mitre-bedford ITERATE
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 25 Mar 85 14:43:21 PST
Received: from mitre-bedford by MIT-MC.ARPA; 25 MAR 85 17:43:15 EST
Date: 25 Mar 1985 17:36:35-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA25113; Mon, 25 Mar 85 08:01:59 est
Date: Mon, 25 Mar 85 08:01:59 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503251301.AA25113@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: ITERATE
If named LET is to replace ITERATE, that is fine with me.
Please make it an essential form.
John
∂25-Mar-85 1757 @MIT-MC:HUDAK@YALE.ARPA CAR and CDR again
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 25 Mar 85 17:57:48 PST
Received: from yale by MIT-MC.ARPA; 25 MAR 85 20:58:07 EST
Received: by YALE-BULLDOG.YALE.ARPA; 24 Mar 85 19:54:45 EST (Sun)
Message-Id: <8503250054.AA23410@YALE-BULLDOG.YALE.ARPA>
Received: from YALE-RING by YALE-RES via CHAOS; Sun, 24 Mar 85 20:00:23 EST
Subject: CAR and CDR again
Date: Sun, 24 Mar 85 20:00:25 EST
From: Paul Hudak <Hudak@YALE.ARPA>
To: CPH%MIT-OZ@MIT-MC
Cc: Scheme@MIT-MC, Jinx%MIT-OZ@MIT-MC
In-Reply-To: CPH%MIT-OZ@MIT-MC.ARPA, Sun, 24 Mar 1985 02:26 EST
Maybe I'm just being old and tired, but I like CAR and CDR! I
would be saddened to see them lost in a wave of "modernization".
Would you consider changing LAMBDA to something else? I think
that CAR, CDR and CONS have the same historical value (as does
COND, I suppose).
LAMBDA derives from the Lambda Calculus, where the association with
lambda expressions is clear. CAR and CDR derive from obscure machine
features whose meaning is not clear. CONS is not so bad because it
is short for CONSTRUCT, although PAIR would probably be better.
Obviously, I like keeping in touch with the past, as long as it
doesn't cloud the thinking of the future. This doesn't seem to be
such a case; might as well call the operations "0" and "1", if you
want to be really, really efficient.
Efficiency, of course, is not the rationale for any of this. It's
choosing a name that makes sense. Why did we choose names like WALK
instead of the "traditional" MAPC or MAPCAR or whatever? Some people
probably feel as bad about loosing those as they would for CAR and CDR.
However, I'm not one to stand in the way of preserving history! I was
curious to see how people felt though, and wanted to see how far Essential
Scheme's modernization effort, which does exist, was willing to go.
-Paul
∂25-Mar-85 1852 GJC@MIT-MC NIL, experience with VAX-NIL, or NIL is nothing to worry about.
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 25 Mar 85 18:42:39 PST
Date: 25 March 1985 21:43-EST
From: George J. Carrette <GJC @ MIT-MC>
Subject: NIL, experience with VAX-NIL, or NIL is nothing to worry about.
To: Bartley%ti-csl.csnet @ CSNET-RELAY
cc: JAR @ MIT-MC, SCHEME @ MIT-MC
In-reply-to: Msg of 25 Mar 1985 1153-CST from David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
I was able to put a rational, i.e. (NOT (EQ 'NIL '())), scheme on
top of both VAX-NIL and LMI Release 2.0, both of which are common-lisp.
In fact, in the inner guts of VAX-NIL we have that () is not a symbol,
and the first distributed versions of NIL (SYMBOLP ()) => (),
but peer presure forced us (at that time Glenn Burke and myself) to
toe-the-line and change, if not the guts, but what the user sees
in the way of a type scheme.
One argument TYPEP is not supported in common-lisp, so the following
output from VAX-NIL should not be suprising:
(TYPEP ()) => NULL
(TYPEP 'FOO) => SI:NON-NULL-SYMBOL
(TYPEP '(FOO)) => SI:SIMPLE-CONS
Of course (SYMBOLP X) <==> (TYPEP X 'SYMBOL)
<==> (TYPEP X '(OR NULL SI:NON-NULL-SYMBOL)).
LISTP is then (TYPEP X '(OR NULL SI:SIMPLE-CONS SI:EXTENDED-CONS)).
The SI:EXTENDED-CONS is something GSB put in for BRANDX, (remember hunks?)
but lets not get into that.
There are of course special type masks cleverly arranged to be used with the
VAX instructions for doing these type unions, so that the most useful cases
of two-argument TYPEP are in-line-coded.
The inner workings of the microcoded lisps such as on the LMI LAMBDA
and TI EXPLORER play similar hacks with NIL. Its just one of those
things. Unfortunately the Common-Lisp committee, of which I felt like
an out-gunned member, had the "guts" to change MEMBER, ASSOC, EQUAL,
*, /, +,↑, but not to address this NIL thing.
If you reread JAR's analysis, and I hope I have provided some hints
into the inner workings of some of the base lisps in question, then
you should see what he is talking about.
∂26-Mar-85 1439 @MIT-MC:linus!ramsdell@mitre-bedford WHEN
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Mar 85 14:38:06 PST
Received: from mitre-bedford by MIT-MC.ARPA; 26 MAR 85 17:38:09 EST
Date: 26 Mar 1985 17:36:00-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA09491; Tue, 26 Mar 85 09:43:17 est
Date: Tue, 26 Mar 85 09:43:17 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503261443.AA09491@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: WHEN
OK, so WHEN is a bad idea. However, I agree with
Jonathan that one armed IF is a bad idea.
John
∂26-Mar-85 1444 @MIT-MC:linus!ramsdell@mitre-bedford LIST?
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Mar 85 14:41:00 PST
Received: from mitre-bedford by MIT-MC.ARPA; 26 MAR 85 17:38:57 EST
Date: 26 Mar 1985 17:36:04-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA09666; Tue, 26 Mar 85 09:54:52 est
Date: Tue, 26 Mar 85 09:54:52 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503261454.AA09666@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: LIST?
Cc: ramsdell
I thought LIST? would be a good name for the predicate
that returns true to the objects generated by LIST,
just an VECTOR? returns true to the objects generated
by VECTOR and PAIR? returns true to the objects generated
by PAIR ... eh ... CONS. Opps! Nevermind.
John
PS Maybe STRING should take a variable number of characters
and returns a string.
(define (string . chars) (list->string chars))
∂26-Mar-85 1501 @MIT-MC:linus!ramsdell@mitre-bedford function names.
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Mar 85 15:01:35 PST
Received: from mitre-bedford by MIT-MC.ARPA; 26 MAR 85 17:39:48 EST
Date: 26 Mar 1985 17:36:09-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA09753; Tue, 26 Mar 85 10:00:27 est
Date: Tue, 26 Mar 85 10:00:27 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503261500.AA09753@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: function names.
It is clear no agreement can be reached about CAR and CDR.
I withdraw the suggested name changes except for:
MAPCAR => MAP and
MAPC => WALK.
Is there disagreement here?
John
∂26-Mar-85 1659 @MIT-MC:KMP@SCRC-STONY-BROOK function names.
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Mar 85 16:59:45 PST
Received: from SCRC-STONY-BROOK by MIT-MC via Chaosnet; 26 MAR 85 19:59:59 EST
Received: from SCRC-RIO-DE-JANEIRO by SCRC-STONY-BROOK via CHAOS with CHAOS-MAIL id 203900; Tue 26-Mar-85 18:28:31-EST
Date: Tue, 26 Mar 85 18:28 EST
From: Kent M Pitman <KMP@SCRC-STONY-BROOK.ARPA>
Subject: function names.
To: linus!ramsdell@MITRE-BEDFORD.ARPA, scheme@MIT-MC.ARPA
In-Reply-To: <8503261500.AA09753@linus.UUCP>
Message-ID: <850326182851.4.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM>
Date: Tue, 26 Mar 85 10:00:27 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503261500.AA09753@linus.UUCP>
Subject: function names.
It is clear no agreement can be reached about CAR and CDR.
I withdraw the suggested name changes except for:
MAPCAR => MAP and
MAPC => WALK.
Is there disagreement here?
I support these name changes (perhaps not surprisingly since
I'm partly responsible for them being that way in T). For those
who are curious about the justification for the MAPCAR->MAP change:
* MAP is nicely generic. You can't later extend MAPCAR to
work on general structures like matrices without having to
apologize for the fact that "successive cars of a matrix"
is not as meaningful as it is for lists.
* Whenever anyone complained to me that MAP had another
meaning and that people would be confused, I would take
them by the arm and drag them into the office of an
unsuspecting person to whom I would say: "Please write
an expression on the board which maps a function F across
a list L." The person would -always- write
(MAPCAR F L)
No one -ever- wrote
(MAP F L)
The reason is that MAP is so uncommon that no one even
bothers to verbally distinguish it from MAPCAR. You have to
say "Please write an expression which calls the function MAP
on arguments which are the function F and the list L." to get
the other behavior. From this I conclude that it is "natural"
for the MAPCAR operation to be called MAP.
The arguments for MAPC->WALK are these:
MAPCAR returns a value which is intended to be used.
MAPC returns a value which is not intended to be used.
MAPCAR takes a function which is not intended to have a side-effect.
MAPC takes a function which is intended to have a side-effect.
These two functions have little more in common than the fact
that their first arg is a function and the second is a list.
Also, the "C" is pretty random (presumably deriving from the "CAR"
in MAPCAR). As with MAPCAR, if MAPC were ever extended to map across
(notice I'm using the word "map" and you -know- what I mean) matrices,
arrays, vectors, etc. then again the "C" would be still harder to
explain.
So we wanted something that connoted `visiting elements' but not
a priori constraining the way those elements were enumerated and
not connoting any idea of return value. WALK was chosen because it's
short, sounds like what it does ("walks around in structures"), etc.
By the way, T uses MAPCDR and WALKCDR to mean the "less common" variants
(MAPLIST and MAP, respectively, so you don't have to look them up). The
fact that the names are longer is appropriate (common things should get
the short names), as is the fact that the term CDR is included (since
these don't make sense to generalize to non-CDRable things (although if
you generalized CDR, they would make sense and their name would still
be fine)).
To help with this convention, T renames Lisp's traditional LAST function
to LASTCDR, so what is sometimes called LASTCAR can be called LAST (for
naming consistency with MAP/MAPCDR, WALK/WALKCDR, NTH/NTHCDR).
It is this sort of regularization of naming which has led users of T to
spontaneously send fan mail saying how much they like the clarity of
expression the new names encourage. (Most other languages I've seen get
mostly gripes about naming and little or no praise.) What gripes we get
are usually nitpicky things where users (having decided things are really
winning) want to encourage us to go the rest of the way toward making
the naming consistent in the places where we hesitated to make choices
which would clearly have made the language even more regular. Almost no
one has complained of missing an old name (especially since for the cases
where they care, it's so easy to define synonyms).
-kmp
∂26-Mar-85 1703 @MIT-MC:KMP@SCRC-STONY-BROOK How to let macros work without defining what a macro is...
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Mar 85 17:03:06 PST
Received: from SCRC-STONY-BROOK by MIT-MC via Chaosnet; 26 MAR 85 20:00:04 EST
Received: from SCRC-RIO-DE-JANEIRO by SCRC-STONY-BROOK via CHAOS with CHAOS-MAIL id 203911; Tue 26-Mar-85 18:59:50-EST
Date: Tue, 26 Mar 85 19:00 EST
From: Kent M Pitman <KMP@SCRC-STONY-BROOK.ARPA>
Subject: How to let macros work without defining what a macro is...
To: Scheme@MIT-MC.ARPA
cc: KMP@SCRC-STONY-BROOK.ARPA
Message-ID: <850326190013.5.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM>
Even though it was not possible to agree on how macros
should be specified in Scheme, I believe it important
that they be provided in some form in all implementations
and have a proposal for a semi-invisible way to do this.
(PRIMITIVE-SYNTAX-EXPAND form) required
Takes any form and returns a form which is guaranteed
not to have any syntax other than that required by
the language.
This function signals an error if it receives a form
which is a user-defined macro. (Hence, this function is
for writing code which is defined only over portable
code). The fact that it only allows "primitive" macros
to be expanded is what makes it not need an ENV argument,
since the primitive language does not allow one to
change the set of special forms.
Actually, there are two variations of this proposal which
are probably consistent. One says that it expands all
levels; the other says that it expands just one level.
I think it really doesn't matter. For consistency with
SYNTAX-EXPAND below, let's assume it doesn't recurse into
the form.
The intent is (though this is not part of the proposal)
that languages providing a macro facility would have a
function:
(SYNTAX-EXPAND form env) optional
Takes any form and a syntax environment and returns
a form which has no other syntax than lisp syntax.
This form will expand macros and call PRIMITIVE-SYNTAX-EXPAND
if the underlying representation makes that necessary.
The result should be a form which contains only primitive forms.
This would allow us to define system extensions which we could
-describe- as macro translations without telling users how those
things were defined. Eg, they might be macros or they might be
special forms. Consider that (function/macro names in this example
being hypothetical, but you'll get the idea I hope):
(WITH-OPEN-FILE (STREAM-VAR FILE-NAME . OPTIONS) . BODY)
might be defined to the user to "be the same as":
(CALL-WITH-OPEN-STREAM (LAMBDA (STREAM-VAR) BODY) FILE-NAME . OPTIONS)
and
(PRIMITIVE-SYNTAX-EXPAND
'(WITH-OPEN-FILE (OUTSTREAM "MY.FILE" 'OUT)
(PRINT "Hi there." OUTSTREAM)))
would be defined to return
(CALL-SYNTAX-EXPAND (LAMBDA (OUTSTREAM) (PRINT "Hi there." OUTSTREAM))
"MY.FILE" 'OUT)
regardless of whether the system actually did that expansion when it
ENCLOSEd the form...
This proposal basically gives the user the ability to maintain the
illusion that there are a fixed set of special forms when he does
code-manipulation even if we later decide that a few extra special forms
would be a good idea. eg, WHEN, UNLESS, etc. would not burden code-walking
writers since (PRIMITIVE-SYNTAX-EXPAND form) would know about those
forms and how to magically make them into something meaningful like COND
or IF (are they both primitive? they wouldn't have to be under this proposal).
This also allows implementations to add new special forms which are not
in standard Scheme but which are still handleable by standard Scheme.
Note well that programs which expect to work on code which might call
user-defined macros would HAVE TO use SYNTAX-EXPAND and could not use
PRIMITIVE-SYNTAX-EXPAND even if PRIMITIVE-SYNTAX-EXPAND would appear to
work, since PRIMITIVE-SYNTAX-EXPAND should NOT be sensitive to any
redefinitions of system primitive special forms that extended Scheme
implementations might allow. That is, if a dialect allowed
(DEFINE-SYNTAX (IF ...) ...variant-definition...)
then
(SYNTAX-EXPAND '(IF ...)) should get the variant expansion but
(PRIMITIVE-SYNTAX-EXPAND '(IF ...)) should get the "standard expansion".
This is completely necessary in order for any of this proposal to make sense.
∂26-Mar-85 1802 @MIT-MC:BARTLEY%ti-csl.csnet@csnet-relay.arpa Missing CSNET messages
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Mar 85 18:02:33 PST
Received: from csnet-relay by MIT-MC.ARPA; 26 MAR 85 20:56:28 EST
Received: from ti-csl by csnet-relay.csnet id ab19022; 26 Mar 85 20:19 EST
Date: 26 Mar 1985 1637-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: Missing CSNET messages
To: Scheme@mit-mc.ARPA
cc: Bartley%ti-csl.csnet@csnet-relay.arpa,
Scheme.users%ti-csl.csnet@csnet-relay.arpa
Received: from csl60 by ti-csl; Tue, 26 Mar 85 19:16 CST
A failure at our end caused TI-CSL to miss messages directed to it
yesterday. Would anyone who sent a message to me (Bartley@TI-CSL) or
indirectly to us through Scheme@MIT-MC please resend their messages?
Senders include:
MW@Brandeis
JAR@MIT-MC
linus!ramsdell...
the CSNET postmaster
GJC@MIT-MC
HUDAK%YALE@MIT-MC.ARPA
I don't know how to interpret some of the addresses that failed. We
apparently received messages for "Scheme@Users" which were rejected. Our
local Scheme group mailing list is Scheme.Users@TI-CSL, if that's what
you're looking for.
Regards,
David Bartley
-------
∂26-Mar-85 1839 @MIT-MC:GJS@MIT-OZ car/cdr
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Mar 85 18:39:40 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 26 MAR 85 21:39:06 EST
Date: Tue 26 Mar 85 21:37:53-EST
From: Gerald Jay Sussman <GJS%MIT-OZ@MIT-MC.ARPA>
Subject: car/cdr
To: hudak@YALE.ARPA
cc: scheme@MIT-MC
I dunno if I ever responded to you about this, but I really like
CAR, CDR, CADADR and all the rest. The special advantage is that they
can be pronounced, so I can say them fast over the phone to someone and
they can be expected to understand what I said. Imagine having to say
"First of Rest of First of Rest" when one can say "CADADR"... The key is
that combinations of "A" and "D" are not tongue-twisters.
I think that this is the only name convention I really am attached to, and
it is NOT for historical (hysterical?) reasons, but pragmatic ones.
-------
∂27-Mar-85 0212 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Re: DRAFT of the Revised Revised Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 02:12:11 PST
Received: from csnet-relay by MIT-MC.ARPA; 27 MAR 85 05:12:36 EST
Received: from unc by csnet-relay.csnet id ac21376; 27 Mar 85 5:04 EST
Received: by unc (4.12/4.7) id AA21906; Wed, 27 Mar 85 01:25:03 est
Date: Wed, 27 Mar 85 01:25:03 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8503270625.AA21906@unc>
To: scheme@mit-mc.ARPA
Subject: Re: DRAFT of the Revised Revised Report
2 & 5) The reason for not having a different name for the one-armed
IF is that we tried very hard to keep the number of special forms to a
minimum. Since they are easily distinguished by the number of
subforms, there is no need to add another. Note that the same
philosophy leads MIT to have named LET, which is exactly (except for
the name) what ITERATE used to be.
I used to have both one-armed "if" and named "let" in my system. I got
tired of explaining that the return value of "if" is defined if there
are two arms but undefined if there is one arm. With "let", I got
tired of explaining that it creates simple bindings in the one case
and performs looping/recursion in the other. "let" is such an important
special form that it is inappropriate to give it two such different
meanings.
If you have two syntaxes for one special form, then you have two special
forms. The only difference is that they are distinguished by more than
just the syntax keyword. If one of the two is a natural extension of the
other, fine, otherwise the situation leads to unwarranted confusion.
(The "number of subforms" is an easy distinction for a compiler, but not
always for the eye. I prefer the distinction to be more obvious.)
Incidentally, I had named "let" in my system to correspond to named
"lambda", so named "let" was easy to explain in terms of named "lambda".
Of course, the destructuring lambda-list syntax blew that away.
Conclusions:
I prefer to include "when" and "unless". Cond is not an acceptable
alternative; it is best used to reduce nesting in long sequences of
"if-then-else-if" expressions. While we're at it, I'd like to see
both "cond" and "case" require an "else" clause.
I also prefer the name "recurse" to "iterate" or named "let", and would
like to see it required by the standard.
..Kent
∂27-Mar-85 0638 @MIT-MC:JINX@MIT-OZ function names.
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 06:38:20 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 27 MAR 85 09:38:40 EST
Date: 27 Mar 1985 09:37 EST (Wed)
Message-ID: <JINX.12098367479.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: linus!ramsdell@MITRE-BEDFORD.ARPA, scheme@MIT-MC.ARPA
Subject: function names.
In-reply-to: Msg of 26 Mar 1985 17:36-EST
Tue 26 Mar 85 10:00:27 est from linus!ramsdell at Mitre-Bedford,
linus!ramsdell (John D. Ramsdell) at Mitre-Bedford
What does WALK stand for? Something like FOR-EACH would be
better (except that it suggests the opposite order for the arguments).
WALK suggests something that performs a tree walk to me.
∂27-Mar-85 0709 @MIT-MC:JINX@MIT-OZ DRAFT of the Revised Revised Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 07:09:34 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 27 MAR 85 10:09:51 EST
Date: 27 Mar 1985 10:08 EST (Wed)
Message-ID: <JINX.12098373078.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Kent Dybvig <dyb%unc.csnet@CSNET-RELAY.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: DRAFT of the Revised Revised Report
In-reply-to: Msg of 27 Mar 1985 01:25-EST from Kent Dybvig <dyb%unc.csnet at csnet-relay.arpa>
(define (number-of-special-forms-in-standard date)
(expt 2 (date->number date)))
Now seriously,
Named let corresponds to named-lambda in the same way that let
corresponds to lambda. If argument list destructuring is not a
problem for let, it is not a problem for named let. If it is, the
only "destructuring" allowed in lambda is for &rest arguments (dot
notation). The syntax for LET can be extended to accept rest
arguments:
Note: Each of the subforms of the binding list of a let must be a
list whose CAR is the identifier and whose CADR is the expression
whose value the identifier will receive. Thus the syntax can be
extended to the following:
(let ((<identifier 1> <exp 1>)
.
.
.
(<identifier n> <exp n>)
<rest identifier> ; Note: no parens
<rest exp 1>
.
.
.
<rest exp m>)
<body>)
The rest identifier can be recognized by not being in a list,
and all forms following it are the expressions whose values will be
collected into the &rest list.
I'm not advocating for this extension in the standard, but any
implementation which wants named-let can easily extend the syntax for
let and named-let so that this "destructuring" is provided.
You may be right in that this means that there are 2 special
forms with the same keyword, but that's alright with me. I don't want
to have to remember 50 thousand different identifiers which are
"special" to ths system, and I cannot use as identifiers in portable
code since I don't know what happens in all implementations when a
lambda-parameter attempts to shadow them.
I have no problems recognizing one-armed ifs. They only
appear in the middle of sequences (sorry, begins) and indentation
allows me to see whether there is a second arm or not.
∂27-Mar-85 0722 @MIT-MC:JINX@MIT-OZ How to let macros work without defining what a macro is...
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 07:21:59 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 27 MAR 85 10:20:54 EST
Date: 27 Mar 1985 10:19 EST (Wed)
Message-ID: <JINX.12098375135.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Kent M Pitman <KMP@SCRC-STONY-BROOK.ARPA>
Cc: Scheme@MIT-MC.ARPA
Subject: How to let macros work without defining what a macro is...
In-reply-to: Msg of 26 Mar 1985 19:00-EST from Kent M Pitman <KMP at SCRC-STONY-BROOK.ARPA>
This assumes that all macros work at the s-expression level,
which is not true in our implementation. The only way to provide both
(especially syntax-expand) in all cases would be to fully reduce to
s-code and then invert to s-expressions. This would imply full
(recursive) expansion always.
In our system macros translate from s-expressions to s-code.
There are a few utilities, however, to emulate s-expression level
macros built on top of this. But macros like COND, LET, etc are never
translated at the s-expression level.
∂27-Mar-85 0727 @MIT-MC:JINX@MIT-OZ LIST? -- LIST
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 07:27:18 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 27 MAR 85 10:24:48 EST
Date: 27 Mar 1985 10:23 EST (Wed)
Message-ID: <JINX.12098375866.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
Subject: LIST? -- LIST
To: linus!ramsdell@MITRE-BEDFORD.ARPA, SCHEME@MIT-MC
LIST? will return true of those objects generated by LIST.
That is precisely the case. The previous proposed definition
for LIST? would return true of things which are not propoer lists, but
LIST can only generate proper lists. Since there is no way (that I
know of) of knowing whether a paricular pair-tree was created by a
call to LIST or not (besides the fact that it seems undesirable), the
only way to make this consistent is for LIST? to return #!true only on
proper lists.
∂27-Mar-85 0808 GJC@MIT-MC plea for macros
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 08:08:32 PST
Date: 27 March 1985 11:08-EST
From: George J. Carrette <GJC @ MIT-MC>
Subject: plea for macros
To: SCHEME @ MIT-MC
How about biting the bullet and admitting macros in a way such that
the language can have only one special form: LAMBDA, and all other
forms are defined as macros, even "IF". (To repeat something I've
either seen in a scheme paper or a scheme compiler:
(IF A B C) => (*IF A (LAMBDA () B) (LAMBDA () C)), where *IF is
a hand-coded SUBR). The proper packaging of macros and macro namespaces
would put a lot of budding languages designers amoung us out of business.
Think of scheme as an OEM oriented language. The designers can supply
not much more than the primitives used a "Structure and Interpretation"
the essential ideas and tools, then all manner of interesting (or not)
things can be built on these without being the responsibility of
the designer.
The fact is that there are very large, useful, and even intrinsically
interesting lisp programs that are built on very few primitives. Case
in point: Macsyma. In order to do Macsyma in what common-lisp provides
I had to write my own versions of: GET, EQUAL, ASSOC, PUTPROP, +, -, /, ↑, \,
MEMBER, MAP, MAPLIST. One page of code, big deal.
∂27-Mar-85 1123 @MIT-MC:BARTLEY%ti-csl.csnet@csnet-relay.arpa Re: ASSERT, ports, and NIL
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 11:23:41 PST
Received: from csnet-relay by MIT-MC.ARPA; 27 MAR 85 14:24:01 EST
Received: from ti-csl by csnet-relay.csnet id ac23602; 27 Mar 85 14:14 EST
Date: 27 Mar 1985 1038-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: Re: ASSERT, ports, and NIL
To: Bartley%ti-csl.csnet@csnet-relay.arpa, Scheme@mit-mc.ARPA
cc: Bartley%ti-csl.csnet@csnet-relay.arpa
In-Reply-To: Your message of 22-Mar-85 1032-CST
Received: from csl60 by ti-csl; Wed, 27 Mar 85 12:16 CST
I'd like to clarify my dilemma concerning NIL. Jonathon Rees has shown,
correctly, that one has no problem meeting both the Common Lisp and
standard Scheme specifications for the empty list when the Scheme developer
is able to affect the implementation of both languages. In that case, the
underlying representation for the empty list is arbitrary (call it #!NULL).
The Scheme reader treats the token NIL as a symbol. The Common Lisp reader
interns the token NIL as #!NULL, and such critical routines as SYMBOLP and
INTERN are modified to pretend that the value named #!NULL is a symbol.
The situation I am concerned about is one in which Scheme is being
implemented on top of an existing Lisp system which we are unable to
modify. This is clearly a short term problem, but quite real while it
lasts, and surely not unique to us. For example, it is a problem with
Scheme implementations in Franz Lisp, and in ZetaLisp on Lisp Machines with
()==NIL hardwired into microcode.
Let me walk through an instance of the problem. Assume an existing Lisp in
which ()==NIL. In Lisp, generate a list; the list will be "terminated"
with the symbol NIL in the last CDR. Pass the list to a Scheme routine,
which cdr's down it until it reaches -- what? Unless #!NULL==NIL, Scheme
can't detect the end of the list with a simple EQ? test. Sharing of list
data between the two languages is effectively ruled out.
Again: I'm not arguing that allowing #!NULL==NIL is "good," because it
certainly isn't. I'm just asking for help in overcoming it and, barring a
true solution, insertion of appropriate language in the revised revised
Report acknowledging that it may be a necessity in some implementations.
Alternatively, we could consider such an implementation a "near Scheme" and
take the long term view that it is an interim step towards a "true Scheme."
My purpose here is to raise the issue and possibly find a solution I hadn't
thought of, not to quibble over legalities.
Regards,
David Bartley
-------
∂27-Mar-85 1140 @MIT-MC:ADAMS@YALE.ARPA Re: DRAFT of the Revised Revised Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 11:40:20 PST
Received: from yale by MIT-MC.ARPA; 27 MAR 85 14:40:41 EST
Received: by YALE-BULLDOG.YALE.ARPA; 27 Mar 85 14:30:17 EST (Wed)
Message-Id: <8503271930.AA25200@YALE-BULLDOG.YALE.ARPA>
Received: from YALE-RING by YALE-RES via CHAOS; Wed, 27 Mar 85 14:28:58 EST
Subject: Re: DRAFT of the Revised Revised Report
Date: Wed, 27 Mar 85 14:29:07 EST
From: Norman Adams <Adams@YALE.ARPA>
To: Kent Dybvig <dyb%unc.csnet@CSNET-RELAY>
Cc: scheme@MIT-MC
In-Reply-To: Kent Dybvig <dyb%unc.csnet@csnet-relay.ARPA>, Wed, 27 Mar 85 01:25:03 est
I also prefer the name "recurse" to "iterate" or named "let", and would
like to see it required by the standard.
As far as I can tell, "recurse" is not (yet!) an English word. I think
"recur" would be better, though even that doesn't seem great.
-------
∂27-Mar-85 1143 @MIT-MC:cth%indiana.csnet@csnet-relay.arpa Re: Draft of R.R. Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 11:43:12 PST
Received: from csnet-relay by MIT-MC.ARPA; 27 MAR 85 14:41:26 EST
Received: from indiana by csnet-relay.csnet id ac23683; 27 Mar 85 14:32 EST
Date: Wed, 27 Mar 85 13:22:21 est
From: Chris Haynes <cth%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA04491; Wed, 27 Mar 85 13:22:21 est
To: scheme@mit-mc.ARPA
Subject: Re: Draft of R.R. Report
We are quite pleased with the report. Its synthesis is particularly
remarkable given the considerable diversity of opinion expressed on the
net. Asside from a few bugs and editorial suggestions communicated
directly to Will (the most significant of which was that we agreed
CALL-WITH-CURRENT-CONTINUATION was essential), our only remaining
difficulties with the proposal are reflected in the following opinions.
Given (1) the failure to specify under what circumstance an escape
procedure invocation will result in closing a port opened with
CALL-WITH-INPUT-FILE or CALL-WITH-OUTPUT-FILE, and (2) the optional
nature of the explicit open and close operations, the result is that
portable code can not be written for applications in which ports must
be closed (often the case with todays operating systems) and escape
procedures must be used (as in a coroutine application). The simplest
solution is to make the open and close operations essential and the
call-with operations optional. (In general, if an essential feature
can not be fully specified, it should always be possible to program
around the uncertainty.) If there is some reason why the open and close
operations can not be essential (which shouuld be spelled out in a
rationale statement), then the call-with functions should close files
*only* when they return to the continuation of their invocation. It
would then be possible to define the open and close operations using
call-with functions and devious application of escape procedures.
READ-CHAR-READY? is more descriptive than LISTEN?. The failure to
specify what it returns at end of file is most unfortunate. We
shouldn't waffle just because Common Lisp got it wrong.
If you need to READ with assurance that you won't block, you have to
write your own reader using READ-CHAR-READY? and READ-CHAR?. How
about adding READ-READY?, which returns true iff an entire parsable
object can be read without blocking. (A system that includes READ-ATOM
should also include READ-ATOM-READY?.)
An alternative to this predicate proliferation is to allow all read
functions to return a distinguished object to indicate blocked input,
as they may return a distinguished object to indicate end-of-file.
Then all we need is a single predicate for this object, say HUNG?.
The inclusion of the same numeric order predicates with and without a
"?" looks terrible--as if we couldn't make up our mind, which is what
standardization is all about. And both forms are essential! We were
among of those who insisted on the simpler (no ?) forms because that is
what we were accustomed to. But we'd rather switch than fight if the
result is such conspicuous failure to standardize. At the very least,
only one form should be essential. Would anyone else be willing to
switch?
#!TRUE, #!FALSE and #!NULL should not be constants. They are
sufficiently ugly in programs that an extra quote mark in front is
hardly worse. If they are required more than occasionally they should
be bound to variables anyway. Why complicate the spartan syntax of
Scheme with such things?
#!NULL is unnecessary, for we already have a prefectly good way of
printing and reading the empty list, (). #!NULL is also misnamed:
traditionally NULL is a predicate and NIL is the empty list.
RECURSE (introduced in Chez Scheme and added to Scheme 84) is much
better than "named let" or ITERATE. If we can not agree, it would
be better if neither RECURSE nor named let were mentioned in the report;
but if the standard says some implementations permit named let, it
should say others permit RECURSE.
DEFINE! and DEFREC! should go away. (Yes, We were among those who
wanted them originally, but they aren't worth it.) We're not fond of
DEFINE either and wish it could go the same way, or at least be
optional.
NUMBER? is redundant, since all all numbers are complex in the
proposal. If NUMBER? is included to allow for future generalization
(quaternions?) or other reasons, then the rationale should be stated.
WHEN is better than no one arm conditional. Having no one arm
conditional is better than having IF's alternative optional. UNLESS we
are better off without.
The interaction of OBJECT-HASH and OBJECT-UNHASH with garbage
collection should be specified. If we can't decide, the whole section
should be deleted.
A unary constructor is so fundamental that it is worth standardizing.
It might be called BOX, REF or CELL. BOX probably would create the
least confusion. Of course, we would also need associated selection,
mutation and predicate functions.
Chris
Dan
∂27-Mar-85 1207 @MIT-MC:GJS@MIT-OZ flames!
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 12:07:38 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 27 MAR 85 15:06:53 EST
Date: Wed 27 Mar 85 15:05:41-EST
From: Gerald Jay Sussman <GJS%MIT-OZ@MIT-MC.ARPA>
Subject: flames!
To: scheme@MIT-MC
Apparently everyone is hot-under-the-collar about one-armed IF!
I cannot, for the life of me, see the harm of having one-armed IF.
It is totally unambiguous, and it does not eat up a reserved word,
what is more, it is useful. The alternative of WHEN is just feeping
creaturism, as far as I can see.
Just to add some fuel to the controversy, let me make a horrifying
suggestion:
(if p q) should be defined.
It should return #!true if p is false, and it should return
the value of q if p is true. This conflicts with no current
usage since everyone agrees that one should not use the value
of a side-effect operation. On the other hand, it gives IF the
value of logical implication, in the boolean case -- an often
useful feature. For example:
(if (if p q) r s)
-------
∂27-Mar-85 1242 @MIT-MC:JINX@MIT-OZ ASSERT, ports, and NIL
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 12:42:00 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 27 MAR 85 15:30:35 EST
Date: 27 Mar 1985 15:27 EST (Wed)
Message-ID: <JINX.12098431230.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: David Bartley <Bartley%ti-csl.csnet@CSNET-RELAY.ARPA>
Cc: Scheme@MIT-MC.ARPA
Subject: ASSERT, ports, and NIL
In-reply-to: Msg of 27 Mar 1985 11:38-EST from David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
I don't understand the problem.
NULL? is essential, and as far as I know it is the only
appropriate way to detect an empty list.
How NULL? is implemented (in terms of EQ?, etc) is irrelevant.
As far as I'm concerned there are multiple list terminators
all of which are NULL?
∂27-Mar-85 1245 @MIT-MC:JINX@MIT-OZ Draft of R.R. Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 12:45:10 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 27 MAR 85 15:38:18 EST
Date: 27 Mar 1985 15:36 EST (Wed)
Message-ID: <JINX.12098432860.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Chris Haynes <cth%indiana.csnet@CSNET-RELAY.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: Draft of R.R. Report
In-reply-to: Msg of 27 Mar 1985 13:22-EST from Chris Haynes <cth%indiana.csnet at csnet-relay.arpa>
I agree that #!NULL is unnecessary, but I don't agree that
#!FALSE, etc should be quoted or that they should be bound to
variables if used often. How come you don't ask for 0 to be quoted or
bound to a variable if used often?
RECURSE has the same bug that ITERATE has. The name implies a
certain behaviour which the process it develops may not conform to. In
particular, I usually use named let for loops, but I also use it for
recursive procedures. The advantage of named let is that its name has
no connotations, and that it reduces the number of "reserved"
keywords.
How am I supposed to define things if both DEFINE! and DEFINE
go away?
While I agree that CELLs are nice, why are they neccesary?
They can easily be emulated with pairs, and any implementation which
really uses them can support them optionally.
∂27-Mar-85 1644 @MIT-MC:linus!ramsdell@mitre-bedford Scheme names
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 16:44:31 PST
Received: from mitre-bedford by MIT-MC.ARPA; 27 MAR 85 19:44:51 EST
Date: 27 Mar 1985 19:39:08-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA25130; Wed, 27 Mar 85 10:45:05 est
Date: Wed, 27 Mar 85 10:45:05 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503271545.AA25130@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: Scheme names
When is said that I thought one armed IF is a bad idea,
I really meant that having both a one armed IF and a two
armed IF called the same thing is a bad idea. I can
live without one armed IF because it is trivial to write
the obvious WHEN macro or use COND. Kent points out that the same
problem occurs with named LET. Thus I withdraw my support
for named LET syntax, and request ITERATE (maybe called LOOP)
become an essential form.
I would like to echo KMP's statements about regularization of
naming in T. It is great! Even with a small programming language
like Scheme, it should be the case that one needs to memorize a
small set of naming rules, from which one can correctly guess the
name of the particular function of interest. With T, I am noticely
less dependent on having a manual by my side.
I find it hard to believe that no standardization of macros is
attempted by the Scheme Report, and hope that KMP's macro suggestion
is given serious consideration.
John
∂27-Mar-85 1726 JAR@MIT-MC NIL, again
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Mar 85 17:26:16 PST
Date: 27 March 1985 20:26-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: NIL, again
To: Bartley%ti-csl.csnet @ CSNET-RELAY
cc: SCHEME @ MIT-MC
Date: 27 Mar 1985 1038-CST
From: David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
Let me walk through an instance of the problem. Assume an existing Lisp in
which ()==NIL. In Lisp, generate a list; the list will be "terminated"
with the symbol NIL in the last CDR. Pass the list to a Scheme routine,
which cdr's down it until it reaches -- what? Unless #!NULL==NIL, Scheme
can't detect the end of the list with a simple EQ? test. Sharing of list
data between the two languages is effectively ruled out.
I don't agree that things are hopeless. I will risk repetition in hope
of promoting understanding; my apologies if this message adds nothing to
what I've already said. To implement Scheme on top of a Lisp which
identifies #!NULL (i.e. (), false) with Lisp's symbol NIL, create a new,
unique object; call it SCHEME:NIL. Use this object to implement "the"
symbol NIL for Scheme. Use the object #!NULL, which in Lisp is a symbol
and in Scheme is not, to represent both the empty list and false in
Scheme.
So you have the following equations:
Lisp: Scheme:
Symbol <=> Symbol-but-not-#!NULL
SCHEME:NIL <=> The symbol NIL
NIL, () <=> (), #!NULL, #!FALSE
The phrase "the symbol NIL" is confusing. You need to say either "the
Scheme symbol NIL" or "the Lisp symbol NIL". Lisp and Scheme may agree
on what the empty list and false are, without agreeing on what "the
symbol NIL" is.
(define (symbol? x)
(and x
(or (eq? x 'nil) ;This code is read using the Scheme reader!
(lisp:symbolp x))))
(define (symbol->string x)
(cond ((eq? x 'nil) "NIL")
((not x) (error ...))
(else (lisp:symbol-name x))))
(define (string->symbol x)
(cond ((string-equal? x "NIL") 'nil)
(else (lisp:intern x *scheme-package*))))
(define (null? x) (lisp:null x))
In Common Lisp, these definitions need not be quite so verbose, if you
arrange for the object SCHEME:NIL to be a Common Lisp symbol whose print
name is "NIL" (not EQ to () !).
I do not believe that you will run into trouble if you take this
approach. Since the list terminator is the same between Lisp and
Scheme, there is no problem sharing list structure.
If you plan to use the Common Lisp reader to read Scheme expressions,
then you are in a bit of trouble; Common Lisp allows some way to define
octathorp read macros (so you can implement Scheme #!..., #I, etc.), but
no way to influence the atom reader. But won't you have all sorts of
trouble with numbers if you don't change the atom reader?
I find it hard to believe that you would not be able to make the trivial
required change (the addition of a single COND clause, no more than two
lines of code!). If this patch is really impossible, and you cannot use
a different reader (another tractable solution), then indeed I agree you
will be forced to equate Scheme's NIL with (). I'm sure that would be
fine as an interim solution. The symbol/false distinction is too
useful, and likely to be too ingrained in programs, to permit deviation
from it in the R.R. (although I agree that legalities are not at issue
here).
Jonathan
∂28-Mar-85 0611 @MIT-MC:KMP@SCRC-STONY-BROOK How to let macros work without defining what a macro is...
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 28 Mar 85 06:11:32 PST
Received: from SCRC-STONY-BROOK by MIT-MC via Chaosnet; 28 MAR 85 09:11:51 EST
Received: from SCRC-RIO-DE-JANEIRO by SCRC-STONY-BROOK via CHAOS with CHAOS-MAIL id 204535; Wed 27-Mar-85 19:34:21-EST
Date: Wed, 27 Mar 85 19:34 EST
From: Kent M Pitman <KMP@SCRC-STONY-BROOK.ARPA>
Subject: How to let macros work without defining what a macro is...
To: JINX@OZ.MIT
cc: Scheme@MIT-MC.ARPA
In-Reply-To: <JINX.12098375135.BABYL@MIT-OZ>
Message-ID: <850327193441.0.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM>
Date: 27 Mar 1985 10:19 EST (Wed)
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
This assumes that all macros work at the s-expression level,
which is not true in our implementation. The only way to provide both
(especially syntax-expand) in all cases would be to fully reduce to
s-code and then invert to s-expressions. This would imply full
(recursive) expansion always.
In our system macros translate from s-expressions to s-code.
There are a few utilities, however, to emulate s-expression level
macros built on top of this. But macros like COND, LET, etc are never
translated at the s-expression level.
No, you missed the point. You can implement these special forms however
you want. What I'm proposing is something that takes forms which may be
in an extended syntax and translates it into a standard syntax.
eg, suppose the only extended forms in some dialect are WHEN and UNLESS.
Regardless of how those are implemented (perhaps directly represented
in S-code, perhaps translated to something else in S-code, whatever),
all you have to provide is (literally) the following function:
(DEFINE (PRIMITIVE-SYNTAX-EXPAND FORM)
(COND ((ATOM FORM) FORM)
((EQ (CAR FORM) 'WHEN)
`(COND (,(CADR FORM) ,@(CDDR FORM))))
((EQ (CAR FORM) 'UNLESS)
`(COND ((NOT ,(CADR FORM)) ,@(CDDR FORM))))
(T FORM)))
You never have to call the function internally in the system. It simply
has to be available for users who want to use it. It must be the
responsibility of system maintainers to keep it up to date so that
code-manipulating tools can be written which assume a fixed number
of special forms and new special forms can later be added to standard
Scheme which do not cause a need to rewrite those tools.
Suppose that the only special forms we could agree on being standard
were LAMBDA, QUOTE, and SETQ. Suppose that someone insisted that
(IF X Y Z)
had to be written
(*IF (LAMBDA () X)
(LAMBDA () Y)
(LAMBDA () Z))
and *IF had to be a function, etc. Assume similar rewrites were suggested
for other special forms. Now consider a user program in a particular
dialect which had extra special forms (eg, DEFINE, COND, ...):
(DEFINE (USED-FREE-IN EXP VAR TAIL?)
(COND ((ATOM VAR) (EQ EXP VAR))
(FLAG
(COND ((NULL EXP) NIL)
((USED-FREE-IN (CAR EXP) VAR NIL) T)
(T
(USED-FREE-IN (CDR EXP) VAR T))))
((EQ (CAR EXP) 'LAMBDA)
(COND ((MEMQ VAR (CADR EXP)) NIL)
(T
(USED-FREE-IN (CDDR EXP) VAR T))))
((EQ (CAR EXP) 'SETQ)
(OR (EQ EXP (CADR FORM))
(USED-FREE-IN (CADDR EXP) VAR NIL)))
((EQ (CAR EXP) 'QUOTE) NIL)
(T
(USED-FREE-IN EXP VAR T))))
If I didn't blow it, this program "works" on input which contains
LAMBDA, SETQ, and QUOTE but does not work on input that contains
COND, etc. It could, however, work on those, too, by simply making it
say:
(DEFINE (USED-FREE-IN EXP VAR TAIL?)
(LET ((EXP (PRIMITIVE-SYNTAX-EXPAND EXP)))
(COND ((ATOM VAR) (EQ EXP VAR))
(FLAG
(COND ((NULL EXP) NIL)
((USED-FREE-IN (CAR EXP) VAR NIL) T)
(T
(USED-FREE-IN (CDR EXP) VAR T))))
((EQ (CAR EXP) 'LAMBDA)
(COND ((MEMQ VAR (CADR EXP)) NIL)
(T
(USED-FREE-IN (CDDR EXP) VAR T))))
((EQ (CAR EXP) 'SETQ)
(OR (EQ EXP (CADR FORM))
(USED-FREE-IN (CADDR EXP) VAR NIL)))
((EQ (CAR EXP) 'QUOTE) NIL)
(T
(USED-FREE-IN EXP VAR T)))))
The user could write PRIMITIVE-SYNTAX-EXPAND himself, but he'd have
to:
(a) Make sure his understanding of the syntax equivalences was
letter perfect (the system implementors have a better chance
of getting this right)
(b) Update the function every time the dialect changed. ie, adding
a special form if PRIMITIVE-SYNTAX-EXPAND is not a system primitive
function is an incompatible change, but is a compatible change
if PRIMITIVE-SYNTAX-EXPAND is kept in synch with available special
forms.
It would be possible to have forms which were not translatable. They
should simply be advertised as such and PRIMITIVE-SYNTAX-EXPAND should err
when it sees them so that the user doesn't think he's winning when he's
not.
Does this make it clearer?
-kmp
∂28-Mar-85 0717 @MIT-MC:HUDAK@YALE.ARPA IF and WHEN
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 28 Mar 85 07:17:19 PST
Received: from yale by MIT-MC.ARPA; 28 MAR 85 10:17:42 EST
Received: by YALE-BULLDOG.YALE.ARPA; 28 Mar 85 10:04:59 EST (Thu)
Message-Id: <8503281504.AA07856@YALE-BULLDOG.YALE.ARPA>
Received: from YALE-RING by YALE-RES via CHAOS; Thu, 28 Mar 85 10:02:02 EST
Subject: IF and WHEN
Date: Thu, 28 Mar 85 10:02:05 EST
From: Paul Hudak <Hudak@YALE.ARPA>
To: scheme@MIT-MC
Cc:
Invalid-Addresses: JINX@OZ.MIT.ARPA (?Invalid domain (host))
The issue of IF vs. WHEN came up when this mailing-list was first
set up, at which time I responded in favor of WHEN. I'd like to say
again why: when I read other people's code and come across an IF,
I almost always search to see if there is a second arm. The bad thing
about this is that if I don't see one I look harder, carefully matching
parens, to make sure I didn't miss it. I don't buy the "indentation"
argument, because one shouldn't trust other people to follow stylistic
conventions. Simply from a readability standpoint, WHEN is a good
idea, but at least we should require that IF have two arms.
"Feeping creaturism" is not always bad...
-Paul
∂28-Mar-85 0753 @MIT-MC:JINX@MIT-OZ IF and WHEN
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 28 Mar 85 07:53:38 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 28 MAR 85 10:53:13 EST
Date: 28 Mar 1985 10:52 EST (Thu)
Message-ID: <JINX.12098643202.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Paul Hudak <Hudak@YALE.ARPA>
Cc: scheme@MIT-MC
Subject: IF and WHEN
In-reply-to: Msg of 28 Mar 1985 10:02-EST from Paul Hudak <Hudak at YALE.ARPA>
Do you use EMACS? If so C-M-F (Lisp or SCheme Modes) does the
job when you're confused. I didn't mean counting parens.
∂28-Mar-85 0803 @MIT-MC:JINX@MIT-OZ syntax-expand
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 28 Mar 85 08:03:50 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 28 MAR 85 11:04:12 EST
Date: 28 Mar 1985 11:02 EST (Thu)
Message-ID: <JINX.12098645186.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
Subject: syntax-expand
To: kmp@MIT-MC
cc: scheme@MIT-MC
I don't think you understood my message. I was not saying
that we shouldn't have them, just that providing single level
expansion (especially for syntax-expand in the presence of macros) may
not be so easy. Since you left open the possibility for full
expansion or single level, I vote for full expansion.
[KMP: Sorry that you'll get this message 3 times, but I spazzed]
∂28-Mar-85 1303 @MIT-MC:HUDAK@YALE.ARPA Re: IF and WHEN
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 28 Mar 85 13:03:04 PST
Received: from yale by MIT-MC.ARPA; 28 MAR 85 15:59:18 EST
Received: by YALE-BULLDOG.YALE.ARPA; 28 Mar 85 15:45:05 EST (Thu)
Message-Id: <8503282045.AA03847@YALE-BULLDOG.YALE.ARPA>
Received: from YALE-RING by YALE-RES via CHAOS; Thu, 28 Mar 85 15:07:00 EST
Subject: Re: IF and WHEN
Date: Thu, 28 Mar 85 15:07:03 EST
From: Paul Hudak <Hudak@YALE.ARPA>
To: Bill Rozas <JINX%MIT-OZ@MIT-MC>
Cc: scheme@MIT-MC
In-Reply-To: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>, 28 Mar 1985 10:52 EST (Thu)
Do you use EMACS?
No. Perhaps I should, but I work on an Apollo.
It occurred to me after sending the message that counting clauses
in an IF is no different than counting them in any other special form,
including bodies of LET, etc. Somehow it always seems worse for an
IF, though, perhaps because people tend to write one-liners using IF.
BTW, where does JINX%MIT-OZ@MIT-MC come from? And how does it relate
to JINX@OZ.MIT which used to work but got rejected on my last message?
Is SCHEME@MIT-MC the only relevant mailing-list for these discussions?
-Paul
∂28-Mar-85 1437 @MIT-MC:linus!ramsdell@mitre-bedford Other names for ITERATE
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 28 Mar 85 14:37:39 PST
Received: from mitre-bedford by MIT-MC.ARPA; 28 MAR 85 17:37:56 EST
Date: 28 Mar 1985 17:36:55-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA06997; Thu, 28 Mar 85 09:27:45 est
Date: Thu, 28 Mar 85 09:27:45 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503281427.AA06997@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: Other names for ITERATE
Here are some synonyms for let that could be
used as replacements for ITERATE. Notice they do not
give any connotation on how the named function will be used.
ALLOW
PROVIDE
ENTITLE
FOSTER
I think the following does looks pretty good.
(ALLOW LOOP ((L L) (SUM 0))
(IF (NULL? L)
SUM
(LOOP (CDR L) (+ (CAR L) SUM))))
John
∂28-Mar-85 1511 @MIT-MC:JINX@MIT-OZ Other names for ITERATE
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 28 Mar 85 15:10:55 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 28 MAR 85 18:11:14 EST
Date: 28 Mar 1985 18:10 EST (Thu)
Message-ID: <JINX.12098722943.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: linus!ramsdell@MITRE-BEDFORD.ARPA, scheme@MIT-MC.ARPA
Subject: Other names for ITERATE
In-reply-to: Msg of 28 Mar 1985 17:36-EST
Thu 28 Mar 85 09:27:45 est from linus!ramsdell at Mitre-Bedford,
linus!ramsdell (John D. Ramsdell) at Mitre-Bedford
Why are you not willing to go one step further and notice ALLOW = LET?
∂28-Mar-85 2248 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Re: flames!
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 28 Mar 85 22:48:48 PST
Received: from csnet-relay by MIT-MC.ARPA; 29 MAR 85 01:49:09 EST
Received: from unc by csnet-relay.csnet id a002999; 29 Mar 85 1:39 EST
Received: by unc (4.12/4.7) id AA03857; Thu, 28 Mar 85 09:35:09 est
Date: Thu, 28 Mar 85 09:35:09 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8503281435.AA03857@unc>
To: GJS%MIT-OZ@mit-mc.ARPA, scheme@mit-mc.ARPA
Subject: Re: flames!
(if (if p q) r s)
Could of course be written:
(if (if p q #!true) r s)
"unless" is a handy special form, in addition to "when":
(unless (zero? x) (set! x (/ 1 x)))
would have to be written as:
(when (not (zero? x)) (set! x (/ 1 x)))
or (shudder):
(if (not (zero? x)) (set! x (/ 1 x)))
It has always bothered me that the "else" part was optional
in the one-or-two-armed-if. Why can't the "then" part be
optional as well?
"when" and "unless" are clean, simple, and unambiguous. They
should both be included in the standard.
∂29-Mar-85 0713 @MIT-MC:cth%indiana.csnet@csnet-relay.arpa ITERATE, DEFINE and CELLs
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 07:13:31 PST
Received: from csnet-relay by MIT-MC.ARPA; 29 MAR 85 10:13:30 EST
Received: from indiana by csnet-relay.csnet id aa05046; 29 Mar 85 10:05 EST
Date: Fri, 29 Mar 85 08:49:59 est
From: Chris Haynes <cth%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA00974; Fri, 29 Mar 85 08:49:59 est
To: scheme@mit-mc.ARPA
Subject: ITERATE, DEFINE and CELLs
> RECURSE has the same bug that ITERATE has. The name implies a
> certain behaviour which the process it develops may not conform to. In
> particular, I usually use named let for loops, but I also use it for
> recursive procedures. The advantage of named let is that its name has
> no connotations, and that it reduces the number of "reserved"
> keywords.
Recursion subsumes iteration, so RECURSE is a good name even if used for
simple iteration, but ITERATE isn't a good name when its use is not
tail-recursive. The *disadvantage* of named let is that its name *does* have
connotation, namely local binding and *not* recursion. Our desire to keep
down the number of keywords should not be at the expense of such confusion.
> How am I supposed to define things if both DEFINE! and DEFINE
> go away?
With SET!, provided one assumes that all identifiers are initially bound in
the global environment, or that SET! can extend the global environment.
With the exception of MIT's Scheme, this is what existing systems do. If MIT
is unwilling to change this, then we are reluctantly stuck with DEFINE.
> While I agree that CELLs are nice, why are they neccesary?
> They can easily be emulated with pairs, and any implementation which
> really uses them can support them optionally.
They take up half as much space as pairs, and have many fundamental uses.
They aren't *absolutely* necessary, but then neither is most of Scheme.
Chris
Dan
∂29-Mar-85 0759 @MIT-MC:dyb%unc.csnet@csnet-relay.arpa Re: Other names for ITERATE
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 07:59:26 PST
Received: from csnet-relay by MIT-MC.ARPA; 29 MAR 85 10:59:38 EST
Received: from unc by csnet-relay.csnet id a005294; 29 Mar 85 10:52 EST
Received: by unc (4.12/4.7)
id AA07930; Fri, 29 Mar 85 09:08:20 est
Date: Fri, 29 Mar 85 09:08:20 est
From: Kent Dybvig <dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8503291408.AA07930@unc>
To: scheme@mit-mc.ARPA
Subject: Re: Other names for ITERATE
How about "spiral" or "cycle"?
Spirals can loop back on themselves, or build up in a recursive
fashion, and the name has no other connotation that I know of.
last I heard, spiral was a word in the English language (though
cdr, ref, cond and cons are not).
Cycle is also a word but may have other connotations.
(spiral f ((x l)) (if (null? l) '() (cons (car l) (f (cdr l)))))
(cycle f ((x l)) (if (null? l) '() (cons (car l) (f (cdr l)))))
∂29-Mar-85 0851 @MIT-MC:GJS@MIT-OZ WHEN, UNLESS, RECURSE, et. al.
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 08:51:08 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 29 MAR 85 11:49:46 EST
Date: Fri, 29 Mar 1985 11:47 EST
Message-ID: <GJS.12098915510.BABYL@MIT-OZ>
From: GJS%MIT-OZ@MIT-MC.ARPA
To: scheme@MIT-MC
Subject: WHEN, UNLESS, RECURSE, et. al.
Rules for Scheme standards:
(1) Entities should not be multiplied beyond necessity. -- William of Occam
(2) Special forms should not be multiplied beyond necessity.
(3) Rules for Scheme standard should not be multiplied beyond necessity.
∂29-Mar-85 0949 @MIT-MC:JINX@MIT-OZ ITERATE, DEFINE and CELLs
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 09:49:19 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 29 MAR 85 12:49:40 EST
Date: 29 Mar 1985 12:49 EST (Fri)
Message-ID: <JINX.12098926678.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Chris Haynes <cth%indiana.csnet@CSNET-RELAY.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: ITERATE, DEFINE and CELLs
In-reply-to: Msg of 29 Mar 1985 08:49-EST from Chris Haynes <cth%indiana.csnet at csnet-relay.arpa>
> Recursion subsumes iteration, so RECURSE is a good name even if used for
> simple iteration, but ITERATE isn't a good name when its use is not
> tail-recursive. The *disadvantage* of named let is that its name *does* have
> connotation, namely local binding and *not* recursion. Our desire to keep
> down the number of keywords should not be at the expense of such confusion.
I disagree. Recursion for me (and most of the MIT-Scheme people) is a
property of a process, not a feature of the particular syntax with
which it was expressed. If forms like DO loops are allowed, there is
no syntactic recursion and no real recursion. One can easily imagine
some dual special form which avoids syntactic recursion while
developing a recursive process when evaluated (executed). RECURSE
(recur) has too many such connotations for me since I view a procedure
as a way of encapsulating a process, and the only interesting thing is
the process, not its syntactic description. This distinction between
procedure and process developed by it is very important, though
irrelevant in most programming languages (without a notion of
reduction vs. subproblem) but not in Scheme. It is further expounded
in "Structure and Interpretation ..." section 1.2.1.
> With SET!, provided one assumes that all identifiers are initially bound in
> the global environment, or that SET! can extend the global environment.
> With the exception of MIT's Scheme, this is what existing systems do. If MIT
> is unwilling to change this, then we are reluctantly stuck with DEFINE.
SET! has too many connotations of side effects and I'm not willing
to acceptit as the primary definition mechanism.
I don't view definition as a side effect. Its interactive
implementation involves one, in the same way that the interpreted
implementation of LETREC involve side effects, only because we don't
know how to do it any better. The side effects do not exist for
internal definitions. In the same way that the implementation of
LETREC is incomplete (it can only find a fixed point in some cases,
not all, and the others are disallowed or give an error), the
implementation of DEFINE is incomplete. Its limitations are no worse
than the limitations of LETREC, yet they meet considerable opposition,
which I don't understand.
Purists in MIT-Scheme advocate for DEFINE to signal an error when
attempting to redefine an already existing identifier in a given
environment. While conceptually this would be not only appropriate
but logical, it has problems in an interactive system when people want
to re-load some code after making some changes to it. It would be
very cumbersome to have to change all DEFINEs into SET!s (though I
sometimes think this should be the case). This is the only reason why
we allow "re-definition" of identifiers (again interactive
constraints).
In a given program there should be no redefinitions (I believe that
our "compiler" will complain, but I'm not sure since I never do it),
and definition should occur before assignment or use. We even have a
stylistic convention (unfortunately not rigidly adhered to) to aid the
user in determining whether the definition is static (the value will
not change), or we are only introducing an identifier for further
assignment. In the latter case no initial value is given, thus
(define foo)
(set! foo 3) ; Initial value for foo, which will change
Means something quite different from
(define foo 3) ; Foo is supposed to be 3
This corresponds to LSET and DEFINE in T, but not imposed by the
system.
As you can see, in neither case does the definition conceptually
involve a side-effect, since in the second it declares a constant, and
in the first it declares an identifier which can be used in
assignments. DEFINE is thus purely declarative, as opposed to SET!
which is imperative. I believe this distinction is very important,
and justifies the keeping of DEFINE (or some such declarative form).
> They take up half as much space as pairs, and have many fundamental uses.
> They aren't *absolutely* necessary, but then neither is most of
Scheme.
I'm willing to accept them in the standard as long as the CELL type
is not required to be disjoint from PAIR (in the same way that
CHARACTER is not required to be disjoint from STRING or INTEGER).
There is actually a reason for this, I can see a few proposed memory
(debugging) utility programs whose implementation depends on the fact
that all pointer objects have at least 2 words of storage, which would
not be the case for CELLS.
If they are addopted I suggest the following names:
(MAKE-CELL VALUE) returns a CELL object with initial content VALUE.
(CELL-CONTENT CELL) returns the content of cell CELL.
(SET-CELL-CONTENT! CELL NEW-VALUE) makes the new content of CELL be
NEW-VALUE.
∂29-Mar-85 0957 @MIT-MC:JINX@MIT-OZ WHEN, UNLESS, RECURSE, et. al.
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 09:56:56 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 29 MAR 85 12:57:18 EST
Date: 29 Mar 1985 12:56 EST (Fri)
Message-ID: <JINX.12098928030.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: GJS%MIT-OZ@MIT-MC.ARPA
Cc: scheme@MIT-MC
Subject: WHEN, UNLESS, RECURSE, et. al.
In-reply-to: Msg of 29 Mar 1985 11:47-EST from GJS
(4) Messages about WHEN, UNLESS, RECURSE, etc should not be multiplied
beyond necessity.
∂29-Mar-85 1214 JAR@MIT-MC ITERATE, DEFINE, WHEN, cells, etc.
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 12:13:53 PST
Date: 29 March 1985 14:09-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: ITERATE, DEFINE, WHEN, cells, etc.
To: SCHEME @ MIT-MC
In-reply-to: Msg of Fri 29 Mar 85 08:49:59 est from Chris Haynes <cth%indiana.csnet at csnet-relay.arpa>
Why are people so hot to change the report? Many of these questions
(such as that of ITERATE and its alternatives) were discussed last fall,
and we agreed that we couldn't agree, so the features got omitted. The
report seems mostly fine to me, and given how strongly people feel about
iteration primitives, DEFINE, and everything else, I don't think it's
worth rocking the boat again. Perhaps not everyone who is participating
in current discussions has an understanding of how strong the
disagreements are, or perhaps they forget that we agreed that
controversial features are to be ommitted, unless their absence gravely
compromises the ability to express programs at all.
If anything, the report should be pruned, not expanded. It is already
much larger than most of us would like it to be. My suggestion that
(IF A B) be changed from essential to optional was an attempt to remove
something I thought was both redundant and controversial, and I thought
it a reasonable suggestion, for symmetry with the optionality of
(DEFINE (F X) Y) ; the fact that there's been so much argument just
supports my proposal that it be removed from the essential dialect! In
any case, I think we should concern ourselves with inconsistencies and
redundancies, not with questions which were settled (by agreeing to not
settle them) long ago. The most serious omissions (numbers, strings,
and I/O) have already been addressed. These other features are simply
not in that class (although I suppose that this meta-point is what the
arguments are about, in part).
Please, be conservative, and consider that if you are likely to meet
implacable opposition, it is probably better to be quiet. If you have a
new proposal which is just so good that you think everyone will like it,
by all means submit it, but remember that most of us are fanatical
minimalists, and have incompatible measures of minimality. Form models
of other peoples' viewpoints and modify your speeches accordingly.
Please forgive me for this outburst, but I felt things were getting a
bit out of hand. This is not to say that many recent messages have not
been reasonable and good.
Jonathan
∂29-Mar-85 1238 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa names
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 12:38:02 PST
Received: from csnet-relay by MIT-MC.ARPA; 29 MAR 85 14:41:06 EST
Received: from indiana by csnet-relay.csnet id a006294; 29 Mar 85 14:32 EST
Date: Fri, 29 Mar 85 12:02:05 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA03416; Fri, 29 Mar 85 12:02:05 est
To: scheme@mit-mc.ARPA
Subject: names
With respect to special forms vs procedures, IF vs IF/WHEN/UNLESS, LET vs
LET/ITERATE, and feeping creaturism, please remember that the keywords of
special forms may be reserved in some implementations and thus cannot be
used as variables in portable code. When I was a Cobol programmer, it
occurred to me that the main reason that experienced Cobol programmers were
so much more productive than inexperienced programmers was that they didn't
have to flip through the list of several hundred reserved words every time
they wanted to name a variable.
Have pity on the poor beginner. I could probably keep fifty de facto
reserved words in mind as I program, though there are more important things
that I ought to keep in mind instead. Beginners, however, are likely to
have trouble remembering the twenty or so we already have.
One of the glories of Scheme is that it gives T (and NIL) back to the
programmer. At last I can use T as a temporary or to stand for time! Now
they threaten to take away WHEN and ITERATE. Arise, programmers, and defend
your namespace!
P.S. I am in sympathy with the idea of making one-armed IF optional rather
than essential. The one-armed IF that acts like material conditional looks
like a feeping creature to me.
If our strongest disagreements have to do with procedure names, then we've
made real progress. I think MAP is much nicer than MAPCAR, and I would like
to see it adopted so we can keep up with the rest of the functional
programming community. MAPC is utterly random, but while WALK is better it
isn't obviously the right thing and it doesn't have MAPC's tradition.
Anyone for STEP, STOMP, JOG, TIPTOE, PROMENADE, TRAVERSE, or VISIT ?
William Clinger
∂29-Mar-85 1537 @MIT-MC:linus!ramsdell@mitre-bedford REC and LETREC
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 15:36:28 PST
Received: from mitre-bedford by MIT-MC.ARPA; 29 MAR 85 18:36:51 EST
Date: 29 Mar 1985 18:36:48-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA19046; Fri, 29 Mar 85 09:08:34 est
Date: Fri, 29 Mar 85 09:08:34 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503291408.AA19046@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: REC and LETREC
An English name for REC is PROCEDURE. After all, that is
what it returns. By the way, is the predicate PROCEDURE?
missing?
Could some one explain why LETREC is preferable to LABELS?
If the name LABELS is so bad, let me suggest alternatives:
LABEL
MARK
TAG
NOTE
GIVE
SUPPLY
PROVIDE ; from the ITERATE suggestion.
ALLOW
John
∂29-Mar-85 1540 @MIT-MC:linus!ramsdell@mitre-bedford rationalized names
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 15:39:54 PST
Received: from mitre-bedford by MIT-MC.ARPA; 29 MAR 85 18:37:03 EST
Date: 29 Mar 1985 18:36:51-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA19092; Fri, 29 Mar 85 09:14:58 est
Date: Fri, 29 Mar 85 09:14:58 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503291414.AA19092@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: rationalized names
How about adding a section on naming conventions,
much like the so named section in the T manual.
Agreeing one these conventions would greatly
increase program portability.
John
∂29-Mar-85 1545 @MIT-MC:linus!ramsdell@mitre-bedford LIST?
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 15:44:57 PST
Received: from mitre-bedford by MIT-MC.ARPA; 29 MAR 85 18:37:51 EST
Date: 29 Mar 1985 18:36:55-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA19122; Fri, 29 Mar 85 09:19:38 est
Date: Fri, 29 Mar 85 09:19:38 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8503291419.AA19122@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: LIST?
Is it agreed that LIST? should be included in the report
and that is should be defined as per Bill Rozas?
Eg. The predicate that returns true to objects generated
by LIST.
John
∂29-Mar-85 1631 @MIT-MC:mw%brandeis.csnet@csnet-relay.arpa Other names for ITERATE
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 16:31:18 PST
Received: from csnet-relay by MIT-MC.ARPA; 29 MAR 85 19:31:38 EST
Received: from brandeis by csnet-relay.csnet id ab07489; 29 Mar 85 19:17 EST
Received: by brandeis.ARPA (4.12/4.7)
id AA03530; Fri, 29 Mar 85 13:37:18 est
Date: 29 Mar 1985 13:30-EST
From: mw%brandeis.csnet@csnet-relay.arpa
In-Real-Life: Mitchell Wand,faculty
Subject: Other names for ITERATE
To: scheme@mit-mc.ARPA
Message-Id: <480969029/mw@brandeis>
How about LABEL? Except for its (obsolescent) use in Lisp and in
imperative languages, it has no other connotations, and it corresponds
nicely to the purported denotational semantics. Furthermore, each of
those uses corresponds to a recursive declaration of some sort.
Thus:
(label foo ((x 0)(y 1)(k (lambda (x) x))) blah)
BTW, "recursion" is the noun form of the verb "recur" (to occur again).
[As vision is the noun form of the verb "view"]. So if you verb
"recursion", you should get "recur", not "recurse", as in: "this
function recurs (not recurses) on the cdr of its argument."
-- Mitch
∂29-Mar-85 2135 @MIT-MC:BARTLEY%ti-csl.csnet@csnet-relay.arpa NIL vs ()
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 21:35:34 PST
Received: from csnet-relay by MIT-MC.ARPA; 30 MAR 85 00:35:45 EST
Received: from ti-csl by csnet-relay.csnet id aa08681; 30 Mar 85 0:24 EST
Date: 29 Mar 1985 1355-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: NIL vs ()
To: Scheme@mit-mc.ARPA
cc: Bartley%ti-csl.csnet@csnet-relay.arpa
Received: from csl60 by ti-csl; Fri, 29 Mar 85 14:27 CST
Thanks to JAR and GJC, I have a clearer idea of how to avoid the problem
I've raised recently. This has been one of those things that could be
cleared up in 10 minutes in person, but has been beset with terminology
problems. I withdraw my request.
Regards,
David Bartley
-------
∂29-Mar-85 2138 @MIT-MC:BARTLEY%ti-csl.csnet@csnet-relay.arpa RE: The revised revised Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Mar 85 21:38:23 PST
Received: from csnet-relay by MIT-MC.ARPA; 30 MAR 85 00:35:54 EST
Received: from ti-csl by csnet-relay.csnet id ac08681; 30 Mar 85 0:24 EST
Date: 29 Mar 1985 1437-CST
From: David Bartley <Bartley%ti-csl.csnet@csnet-relay.arpa>
Subject: RE: The revised revised Report
To: Scheme@mit-mc.ARPA
cc: Bartley%ti-csl.csnet@csnet-relay.arpa
Received: from csl60 by ti-csl; Fri, 29 Mar 85 15:00 CST
Here are my votes on some of the issues swirling around the Scheme World
these days...
-- I strongly prefer the term "port."
-- I prefer the names CAR and CDR to anything else I've heard. I am
partly motivated by the desire to woo others away from inferior forms of
Lisp; avoiding such changes may help.
-- I prefer MAP and WALK to MAPCAR and MAPC. Common Lisp's MAP is a
generalization of MAPCAR, so I don't see any problem there. WALK is more
meaningful than MAPC. WALK should be optional; MAP may be either essential
or optional.
-- Both IF and WHEN are worthwhile. "One-armed" IF and WHEN should both
be optional. I use WHEN exclusively for side effects and the choice of the
name helps clarify my intent. I don't like UNLESS, because it adds nothing
new, but making it optional is OK by me.
-- I'd like to modify EQV? slightly to align it with Common Lisp's EQL.
I believe the only difference is that EQL "does the right thing" for
character data objects as well as for numbers. Does anyone oppose this?
-- I am worried about PRIMITIVE-SYNTAX-EXPAND. It "feels" like too
little, too late in the game. I'd rather allow time for this issue to gel
further.
-- It has been suggested that LAMBDA be the only special form. Unless we
tackle the subject of macros in detail, I can't imagine subcategorizing
special forms into "real" special forms and "other" special forms, some of
which may be macros.
-- I prefer named LET to ITERATE or RECURSE. ITERATE is inadequate, while
RECURSE is poor English. If we can't agree, lets make named LET and
perhaps one of the alternatives both optional (as Dan and Chris suggest).
-- Let's drop LIST?. It's both expensive and unimportant. Make it
optional if you'd like.
-- I like READ-CHAR-READY?.
-- I don't like READ-READY?. Its implementation would seem to require
buffering all of the characters going into a READ just in case we find they
don't add up to an entire parsable object. HUNG? has the same problem.
-- I agree that = and =? shouldn't both be essential. I'm willing to
switch to the '?' forms if necessary, although I prefer the others for
compatibility with the Abelson and Sussman book and with Common Lisp.
-- Let's drop #!NULL. #!FALSE and () suffice.
-- I'm willing to lose DEFINE! and DEFREC!, as Chris and Dan suggest.
-- I favor retaining NUMBER?.
-- OBJECT-HASH and OBJECT-UNHASH should be optional.
-- I prefer REF over CELL (and CELL over BOX). It should be optional. In
our work, we are also concerned about locatives and forwarding pointers, so
it isn't clear to us that REF alone is interesting.
Regards,
David Bartley
-------
∂30-Mar-85 0047 @MIT-MC:CPH@MIT-OZ ITERATE, DEFINE and CELLs
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 30 Mar 85 00:46:55 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 30 MAR 85 03:47:23 EST
Date: Sat, 30 Mar 1985 03:46 EST
Message-ID: <CPH.12099090096.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Chris Haynes <cth%indiana.csnet@CSNET-RELAY.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: ITERATE, DEFINE and CELLs
In-reply-to: Msg of 29 Mar 1985 08:49-EST from Chris Haynes <cth%indiana.csnet at csnet-relay.arpa>
Date: Friday, 29 March 1985 08:49-EST
From: Chris Haynes <cth%indiana.csnet at csnet-relay.arpa>
> How am I supposed to define things if both DEFINE! and DEFINE
> go away?
With SET!, provided one assumes that all identifiers are initially
bound in the global environment, or that SET! can extend the
global environment. With the exception of MIT's Scheme, this is
what existing systems do. If MIT is unwilling to change this,
then we are reluctantly stuck with DEFINE.
This is a terrible idea. It seems that the ability to have many
different environments in which to perform incremental definitions has
been consistently overlooked by almost everyone except MIT Scheme and
T. Anyone who has ever tried to program a BIG system, and by that I
mean something over 500-1000 pages of code, knows that this kind of
packaging is **ESSENTIAL**!! So please don't try to take this away.
∂30-Mar-85 0054 @MIT-MC:CPH@MIT-OZ The revised revised Report
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 30 Mar 85 00:53:52 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 30 MAR 85 03:54:03 EST
Date: Sat, 30 Mar 1985 03:53 EST
Message-ID: <CPH.12099091315.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: David Bartley <Bartley%ti-csl.csnet@CSNET-RELAY.ARPA>
Cc: Scheme@MIT-MC.ARPA
Subject: The revised revised Report
In-reply-to: Msg of 29 Mar 1985 15:37-EST from David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
Regarding your most recent set of (about 15) suggestions: I agree
completely with every single one of them. Thank you.
∂31-Mar-85 1822 JAR@MIT-MC REC and LETREC
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 31 Mar 85 18:22:26 PST
Date: 31 March 1985 21:22-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: REC and LETREC
To: JDR @ MIT-MC
cc: SCHEME @ MIT-MC
Date: 29 Mar 1985 18:36:48-EST
From: linus!ramsdell at Mitre-Bedford
By the way, is the predicate PROCEDURE? missing?
It is intentionally missing; the decision to omit it was the outcome of
a discussion at the workshop. As I remember, it was decided that it was
unnecessary, and certain people (me) thought it was possibly meaningless
and/or harmful.
Could some one explain why LETREC is preferable to LABELS?
It was decided that a way to introduce local recursive definitions was
absolutely necessary; DEFINE of course being out of the question, there
was a heated debate between the names LABELS and LETREC, the LABELS
people arguing for English words and respect for the 1978 Revised Report
and Common Lisp, and the LETREC people arguing for something more
descriptive and allegedly pervasive in FP literature. The LABELS camp
(me) was overwhelmed, so LETREC it is. Let us be happy there was any
agreement at all.
Jonathan
∂31-Mar-85 1834 JAR@MIT-MC READ-CHAR-READY?
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 31 Mar 85 18:34:31 PST
Date: 31 March 1985 21:34-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: READ-CHAR-READY?
To: SCHEME @ MIT-MC
In-reply-to: Msg of 29 Mar 1985 1437-CST from David Bartley <Bartley%ti-csl.csnet at csnet-relay.arpa>
I have a little trouble reading READ-CHAR-READY? ; it sounds like it
ought to be an imperative (read a ready character), until you get to
the question mark, and then it's hard to know what to think. How about
something that sounds like it's asking a question? Something like:
WOULD-THE-READ-CHAR-PROCEDURE-BLOCK-IF-I-CALLED-IT? only shorter.
How about INPUT-AVAILABLE? or IMMEDIATELY-READABLE? or
READABLE-WITHOUT-BLOCKING? or something like that. Does anyone else
like INPUT-AVAILABLE? ? This is what it was always supposed to be
called in Yale Scheme, except that it never got implemented.
Jonathan
∂31-Mar-85 2042 @MIT-MC:cth%indiana.csnet@csnet-relay.arpa REC and LETREC
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 31 Mar 85 20:42:29 PST
Received: from csnet-relay by MIT-MC.ARPA; 31 MAR 85 23:42:10 EST
Received: from indiana by csnet-relay.csnet id ab16620; 31 Mar 85 23:28 EST
Date: Sun, 31 Mar 85 16:22:40 est
From: Chris Haynes <cth%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA03507; Sun, 31 Mar 85 16:22:40 est
To: purdue!ihnp4!linus!ramsdell@mitre-bedf
Subject: REC and LETREC
Cc: scheme@mit-mc.ARPA
> linus!ramsdell@mitre-bedf / 11:41 pm Mar 29, 1985 ****/
>
> An English name for REC is PROCEDURE. After all, that is
> what it returns. By the way, is the predicate PROCEDURE?
> missing?
REC may not return a procedure, as in
(rec foo (cons exp (lambda () ...foo...))).
I think we agreed to omit PROCEDURE?, since it doesn't do much good to
know something is a procedure (without knowing how many args it wants,
whether it ever returns, etc.).
> Could some one explain why LETREC is preferable to LABELS?
LETREC is what it seems, a recursive variant of LET. LABELS? only
expresses that it has something to do with naming (labeling) things.
Chris
∂31-Mar-85 2045 @MIT-MC:cth%indiana.csnet@csnet-relay.arpa JINX reply on RECUR, DEFINE, ...
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 31 Mar 85 20:44:53 PST
Received: from csnet-relay by MIT-MC.ARPA; 31 MAR 85 23:42:15 EST
Received: from indiana by csnet-relay.csnet id ac16620; 31 Mar 85 23:29 EST
Date: Sun, 31 Mar 85 20:07:15 est
From: Chris Haynes <cth%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA02538; Sun, 31 Mar 85 20:07:15 est
To: scheme@mit-mc.ARPA
Subject: JINX reply on RECUR, DEFINE, ...
> Recursion for me (and most of the MIT-Scheme people) is a
> property of a process, not a feature of the particular syntax with
> which it was expressed.
We agree that the distinction between process and program is
fundamental. But RECUR (Mitch's comment that RECURSE isn't English is
well taken) is at least expressive of the program (and has the
pedagogic virtue of emphasizing that program recursion expresses both
recursion and iteration of processes). Local recursion (or iteration)
is too fundamental to be subsumed by LET, which expresses local
binding, *not* recursion (or iteration).
We like Mitch's LABEL suggestion much better than named LET, but prefer
RECUR.
> SET! has too many connotations of side effects and I'm not willing
> to accept it as the primary definition mechanism.
>
> I don't view definition as a side effect. Its interactive
> implementation involves one, in the same way that the interpreted
> implementation of LETREC involve side effects, only because we don't
> know how to do it any better...
>
> Purists in MIT-Scheme advocate for DEFINE to signal an error when
> attempting to redefine an already existing identifier in a given
> environment...
Your thorough justification of MIT's rationale is appreciated. If
DEFINE could not be used to redefine existing bindings, we would have no
problem with it. If the standard said that some systems may not permit
such redefinitions, we'd feel better about DEFINE being essential.
(Though most systems would allow redefinitions to ease reloading, as
you indicated.)
Your analogy with LETREC is not as close as you make it seem, for all
code within the scope of a LETREC is known at compile time, and the
same is not true for top level bindings. (This is also the root of the
problem we have with the use of DEFINE as a substitute for LETREC.)
LETREC bindings are always new, never mutations of existing bindings.
> I'm willing to accept them in the standard as long as the CELL type
> is not required to be disjoint from PAIR (in the same way that
> CHARACTER is not required to be disjoint from STRING or INTEGER)...
>
> If they are adopted I suggest the following names:
>
> (MAKE-CELL VALUE) returns a CELL object with initial content VALUE.
>
> (CELL-CONTENT CELL) returns the content of cell CELL.
>
> (SET-CELL-CONTENT! CELL NEW-VALUE) makes the new content of CELL be
> NEW-VALUE.
We don't mind lack of disjointness. The names you propose are better
than none at all, but not our favorites (here we go again...); we use
them a lot (sometimes more than explicit cons cells) and would like
shorter names. BOX and REF have the advantage that UNBOX and DEREF
make sense, and SET-{CELL|BOX|REF}! is enough for mutation. We don't
have to say CONS-CONTENT, or SET-CONS-CONTENT!.
We know everyone has had about enough of these name debates, but they have
served the useful purpose of clarifying our rationales. We appreciate
Johnathan's restatement of the principle that if we can not agree after
making our rationales clear, then the standard should try to avoid
mentioning the points of contention. This indicates that neither named
LET nor RECUR be mentioned. DEFINE could stay, since that seems to be
the concensus, but it would be nice if its redefinition capability were
optional.
Chris
Dan
∂31-Mar-85 2047 @MIT-MC:cth%indiana.csnet@csnet-relay.arpa CPH reply on DEFINE
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 31 Mar 85 20:47:28 PST
Received: from csnet-relay by MIT-MC.ARPA; 31 MAR 85 23:42:19 EST
Received: from indiana by csnet-relay.csnet id ad16620; 31 Mar 85 23:29 EST
Date: Sun, 31 Mar 85 20:08:00 est
From: Chris Haynes <cth%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA02544; Sun, 31 Mar 85 20:08:00 est
To: scheme@mit-mc.ARPA
Subject: CPH reply on DEFINE
> CPH%MIT-OZ@MIT-MC.ARPA / 9:33 am Mar 30, 1985 ****/
>
> It seems that the ability to have many
> different environments in which to perform incremental definitions has
> been consistently overlooked by almost everyone except MIT Scheme and
> T. Anyone who has ever tried to program a BIG system, and by that I
> mean something over 500-1000 pages of code, knows that this kind of
> packaging is **ESSENTIAL**!! So please don't try to take this away.
We grant the importance of such a facility, and are not trying to take it
way; but there is no concensus on how to provide such a facility, so it
is too soon to standardize on one. (Similarly, syntactic extensions
are **ESSENTIAL** to the kind of thing we do here; but it is also too soon
to standardize on a syntactic extension mechanism.)
We were simply debating whether SET! should be required to extend the
global environment if its identifier is unbound (or equivalently, have
everything bound in the global environment to begin with). This would
make DEFINE unessential, though it might still be optional. It has
nothing to do with multiple environments for incremental definition,
except that MIT uses DEFINE for both purposes.
Chris
Dan
∂01-Apr-85 2047 JAR@MIT-MC CPH reply on DEFINE
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 1 Apr 85 20:47:02 PST
Date: 1 April 1985 23:46-EST
From: Jonathan A Rees <JAR @ MIT-MC>
Subject: CPH reply on DEFINE
To: cth%indiana.csnet @ CSNET-RELAY
cc: SCHEME @ MIT-MC
In-reply-to: Msg of Sun 31 Mar 85 20:08:00 est from Chris Haynes <cth%indiana.csnet at csnet-relay.arpa>
Date: Sun, 31 Mar 85 20:08:00 est
From: Chris Haynes <cth%indiana.csnet at csnet-relay.arpa>
We were simply debating whether SET! should be required to extend the
global environment if its identifier is unbound (or equivalently, have
everything bound in the global environment to begin with). This would
make DEFINE unessential, though it might still be optional. It has
nothing to do with multiple environments for incremental definition,
except that MIT uses DEFINE for both purposes.
I think that people at MIT and at Yale generally believe that SET!
should NOT cause the variable assigned to become bound in ANY
environment (global or otherwise) if it wasn't already. Although MIT
Scheme's idea of environments argues for this position, there are these
other reasons: (1) taste - who wants to see all those side-effects all
over the place?; (2) one form one function - DEFINE binds, SET!
updates.
While I appreciate your desire to simplify things, DEFINE and SET! are
viewed here as two totally different operations, so I think they should
remain separate & required, as we agreed last fall.
Jonathan
∂02-Apr-85 0005 @MIT-MC:CPH@MIT-OZ CPH reply on DEFINE
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 2 Apr 85 00:05:44 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 2 APR 85 03:05:44 EST
Date: Tue, 2 Apr 1985 03:05 EST
Message-ID: <CPH.12099869022.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Chris Haynes <cth%indiana.csnet@CSNET-RELAY.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: CPH reply on DEFINE
In-reply-to: Msg of 31 Mar 1985 20:08-EST from Chris Haynes <cth%indiana.csnet at csnet-relay.arpa>
My apologies for the rather careless wording of my earlier message.
What I wanted to say was: if SET! extends the "global" environment,
then that environment has become special in that it is the ONLY
environment that can be extended by interactive definition. This
would seem to preclude the existence of many such environments.
DEFINE eliminates the problem, because it specifies, very precisely,
the environment in which the name is bound.
∂09-Apr-85 0637 @MIT-MC:wagle%indiana.csnet@csnet-relay.arpa First Class Environments and Their Extenders
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Apr 85 06:36:58 PST
Received: from csnet-relay by MIT-MC.ARPA; 9 APR 85 09:37:06 EST
Received: from indiana by csnet-relay.csnet id a001256; 9 Apr 85 9:36 EST
Date: Tue, 9 Apr 85 02:35:36 est
From: Perry Wagle <wagle%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA15319; Tue, 9 Apr 85 02:35:36 est
To: scheme%indiana.csnet@csnet-relay.arpa
Subject: First Class Environments and Their Extenders
My ATN (Augmented Transition Network) is a macro that makes a grammar into
an object. This object (currently) is a closure taking one argument that is
evaluated in an environment where each state has been transformed into a
function of (currently) five arguments using letrec. Roughly:
(define-atn my-atn state2 (state1 arc1 arc2) (state2 arc3 arc4))
is transformed to:
(letrec ((state1 (lambda (...) (nexus arc1 arc2)))
(state2 (lambda (...) (nexus arc3 arc4))) )
(define! my-atn
(lambda (*sentence*) (state2 ...))))
where the "..." means "fill in the blank". NEXUS is a macro that determines
the evaluation order of the arcs (depth-first, breadth-first, parallel, etc).
One problem with this is that if I have a large ATN (with say 100 states,
and an average branching factor of 5), the compile can take a significant
amount of time, even if I have a VAX 780 all to myself at 3AM.
How do you debug the grammar. Well, first you find the state in which it
failed, you modify the source code of the grammar, and then you recompile
the ENTIRE GRAMMAR. Yuck!
The standard solution to this in the literature of ATNs (and AI in
general) seems to be to define each state as a global-binding, and not to
worry about trying to package them all up in objects. I don't like this
because its not modular -- the inards of each compiled atn-grammar is
sprawled out everywhere. I have several different atn-grammars, and I
don't want to worry about them interfering with one another.
The letrec method is a nice method, and I would like to make it work.
My current view of what I think I want is this: That letrec in the
right-hand-side of the transformation at the beginning of this note defined
a new rib (MY←RIB) in front of the "current" environment (OLDENV) creating a
new environment (MY←ENV). I want to rebind variables in MY←RIB to
expressions EVALuated in MY←ENV, and I want to extend MY←RIB with new
variables bound to the evaluations of expressions EVALuated in MY←ENV (with
MY←ENV already extended by the new variable (which is initially bound to
something like '#!unspecified', then rebound to the new value -- that is,
normal letrec semantics). I could then create functions (macros?) like
'editstate', 'addstate', 'trace-state', 'untrace-state', etc. that would do
the obvious things to a particular compiled-atn-grammar. This way, I only
have to recompile the state, not the entire grammar.
Put another way, I can modify the grammar interactively rather than in
batch mode like I am now.
PS -- I designed it this way, because I heard that first class environments
were on their way, and I thought it would eventually work the way I wanted
it too. But apparently now, the idea is that you should ONLY be able to
extend the LAST rib in the rib sequence. Seeing as how I want to extend the
second to the last rib (and two is an arbitrary number), and there being a
number of programming technique reasons for putting new ribs between me and
the second to the last rib, I have to object and call for a facility
something like 'call-with-current-rib-set!' (where set! is rebind
and extend as one), and I need to EVAL (compile, execute) in the proper
environment, MY←ENV, which is not necessarily equal to the current one, and
is procured with something like 'call-with-current-environment'.
'call/c←rib' is not necessarily incompatable with 'call/c←env' (as I almost
thought) as I can:
(let ((MY←RIB (call/c←rib (lambda (x) x)))
(MY←ENV (call/c←env (lambda (x) x))) )
(some function of MY←RIB and MY←ENV here) )
As long as I can grab a rib extender, and EVAL in a environment other than
the current one, everything is fine. The call/c←rib and call/c←env is just
illustration.
As I think that this generalizes to objects (modules), I don't think calls
to rewrite my ATN are in order unless they make the same generalization.
∂10-Apr-85 0107 @MIT-MC:CPH@MIT-OZ First Class Environments and Their Extenders
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 10 Apr 85 01:06:32 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 10 APR 85 04:06:27 EST
Date: Wed, 10 Apr 1985 04:07 EST
Message-ID: <CPH.12101977358.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Perry Wagle <wagle%indiana.csnet@CSNET-RELAY.ARPA>
Cc: Scheme@MIT-MC
Subject: First Class Environments and Their Extenders
In-reply-to: Msg of 9 Apr 1985 02:35-EST from Perry Wagle <wagle%indiana.csnet at csnet-relay.arpa>
Why did your message get sent to this mailing list? I think that
there must have been some mistake as it seems to be inappropriate to
the purpose of the mailing list, which is a forum for the Scheme
report proposal.
∂21-Apr-85 0652 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa if, mapcar, mapc, ...
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Apr 85 06:51:52 PST
Received: from csnet-relay by MIT-MC.ARPA; 21 APR 85 09:52:11 EST
Received: from indiana by csnet-relay.csnet id a026012; 21 Apr 85 9:54 EST
Date: Sat, 20 Apr 85 15:28:35 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA04262; Sat, 20 Apr 85 15:28:35 est
To: scheme@mit-mc.ARPA
Subject: if, mapcar, mapc, ...
This note proposes a few significant changes and corrections to
the draft of the "Revised Revised Report". Let me know if I have
misread the consensus.
I am moving to Oregon in two weeks. I expect June will arrive
before I have finished typesetting this thing.
William Clinger
----------------------------------------------------------------
Following the Algol 60 report, I propose that all attendees at
the Brandeis workshop be listed as authors. The acknowledgements
will list other participants in the discussion over the network,
and I will sign an editor's note accepting blame for errors in
transcription and interpretation.
Chris Hanson's revised report on strings will be incorporated.
In resonse to a few complaints, I would like to replace the last
paragraph in Section I.0 ("Brief history of Scheme") with:
Scheme shares with Common Lisp [\ref] the goal of a core
language common to several implementations. Scheme differs
from Common Lisp in its emphasis upon simplicity and
function over compatibility with older dialects of Lisp.
To allow for less error checking in compiled code, in the
discussion of variable references in section II.1 "An error is
signalled if {\it variable} is unbound" should read "It is an
error if {\it variable} is unbound".
Two-armed if will change from essential to optional status.
In the discussion of cond, "The special keyword {\tt else} may be
used..." should read "The keyword or variable {\tt else} may be
used...".
define! and defrec! will be flushed altogether.
The rationale for set! will be flushed.
In the header line for backquote, "macro special form" should be
"special form".
The initial value for nil (if it is provided at all) should be
#!null rather than #!false.
Several people have asked that append! not be allowed to side
effect its last argument, so unless there is opposition that
change will be made.
See my separate note for the proposed lexical syntax of numbers
and some questions that I have concerning numbers.
There is a problem with object-hash and object-unhash. People
might want to ask themselves whether object-unhash is really useful.
The following scenario will be added to the rationale:
>>>(define x (cons 0 0))
x
>>>(object-hash x)
77
>>>(set! x 0)
...
>>>(gc) ; garbage collection occurs for some reason
...
>>>(object-unhash 77)
??? ; ill-defined: #!false or (0 . 0)
The name of mapcar will be changed to map. (There seems to be a
fair consensus for this.)
The name of mapc will be changed to for-each. (There seems to be
a fair consensus that it should be changed, and for-each seems to
me to be the best name that has been proposed. At any rate it is
the only name that has been proposed that has not drawn
objections.)
call-with-current-continuation is essential. That it was not so
indicated in the draft was a gross blunder.
The introductory material for call-with-current-continuation will
be moved to the rationale. The last sentence of the rationale,
which begins "Some people think...", will be changed to read
"Although the name is descriptive, some people feel it is too
long and have taken to calling the procedure call/cc".
The original explanation of call-with-input-file and
call-with-output-file allows the port to be closed on any throw.
This makes it impossible to use escape procedures in a portable
manner. The sentence beginning "If the current continuation ever
changes in such a way as to make it doubtful that the procedure
will return..." will therefore change to "The implementation must
not close the port unless it can prove that the port will never
again be used for a read or write operation."
eof? will be renamed eof-object?
listen? will be renamed char-ready?. (Everyone agreed that the
name should be changed, but there was little agreement on the new
name. No one seemed to care very much either.) It will be
required that if char-ready? returns #!true, then the next
read-char operation on the port must not hang, and it will be
pointed out that this has implications for the way that rubout
handlers are written.
It will be required that the load procedure does not affect the
values returned by current-input-port and current-output-port.
There are many small improvements and corrections to be made
also, but I won't bore you with them. (The above should
suffice.)
∂21-Apr-85 0654 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa lexical syntax for numbers
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Apr 85 06:54:22 PST
Received: from csnet-relay by MIT-MC.ARPA; 21 APR 85 09:52:17 EST
Received: from indiana by csnet-relay.csnet id aa26012; 21 Apr 85 9:54 EST
Date: Sat, 20 Apr 85 15:33:46 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA04306; Sat, 20 Apr 85 15:33:46 est
To: scheme@mit-mc.ARPA
Subject: lexical syntax for numbers
A proposed lexical syntax for Scheme numbers.
The draft of the Revised Revised Report did not specify a lexical
syntax for numbers. This proposal is consistent with the draft
but it incorporates a large number of rather arbitrary decisions
that are likely to be controversial. Feel free to controverse.
Actually there are two proposals. The first proposal is for full
(optional) Scheme and the second is for essential Scheme.
(Implementations would be free to implement anything in between
or to extend the syntax so long as the extended syntax didn't
conflict with the optional syntax, right?)
x* means zero or more occurrences of x.
Spaces never appear inside a number, so all spaces in the syntax
are for legibility.
<empty> is the empty string.
bit --> 0 | 1
oct --> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
dit --> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
hit --> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
| a | b | c | d | e | f
| A | B | C | D | E | F
radix2 --> #b | #B
radix8 --> #o | #O
radix10 --> <empty> | #d | #D
radix16 --> #h | #H
exactness --> <empty> | #i | #I | #e | #E
precision --> <empty> | #s | #S | #l | #L
prefix2 --> radix2 exactness precision | radix2 precision exactness
| exactness radix2 precision | exactness precision radix2
| precision radix2 exactness | precision exactness radix2
prefix8 --> radix8 exactness precision | radix8 precision exactness
| exactness radix8 precision | exactness precision radix8
| precision radix8 exactness | precision exactness radix8
prefix10 --> radix10 exactness precision | radix10 precision exactness
| exactness radix10 precision | exactness precision radix10
| precision radix10 exactness | precision exactness radix10
prefix16 --> radix16 exactness precision | radix16 precision exactness
| exactness radix16 precision | exactness precision radix16
| precision radix16 exactness | precision exactness radix16
sign --> <empty> | + | -
suffix --> <empty> | e d d* | E d d* | e - d d* | E - d d*
ureal --> prefix2 bit bit* #* suffix
| prefix2 bit bit* #* / bit bit* #* suffix
| prefix2 . bit bit* #* suffix
| prefix2 bit bit* . bit* #* suffix
| prefix2 bit bit* #* . #* suffix
| prefix8 oct oct* #* suffix
| prefix8 oct oct* #* / oct oct* #* suffix
| prefix8 . oct oct* #* suffix
| prefix8 oct oct* . oct* #* suffix
| prefix8 oct oct* #* . #* suffix
| prefix10 dit dit* #* suffix
| prefix10 dit dit* #* / dit dit* #* suffix
| prefix10 . dit dit* #* suffix
| prefix10 dit dit* . dit* #* suffix
| prefix10 dit dit* #* . #* suffix
| prefix16 hit hit* #* suffix
| prefix16 hit hit* #* / hit hit* #* suffix
| prefix16 . hit hit* #* suffix
| prefix16 hit hit* . hit* #* suffix
| prefix16 hit hit* #* . #* suffix
real --> sign ureal
number --> real | real + ureal i | real - ureal i | real @ real
Some consequences of this syntax are reported below. Please keep
in mind that when I say a syntax is "illegal", I mean that it is
not generated by the syntax above and is therefore not a number
in (full optional) Scheme. The syntax could represent a legal
symbol or even a legal number in an extended Scheme.
Consequences:
Exponents are always in base 10.
Exponents may not have explicit + signs.
e+4 is illegal
1E+3 is illegal
#d+3 is illegal
4-+5i is illegal
4#.5 is illegal
#d5/#o10 is illegal
-4/-5 is illegal
#o5/10 is .625
#s4 is legal
#s#i#b.10##-#x#L#Ea.bi is legal
The proposal for essential Scheme:
dit --> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
sign --> <empty> | + | -
number --> sign dit dit*
Question about exactness: In an implementation that doesn't keep
track of exactness, the exact? predicate should always return
#!false. Right?
William Clinger
willc@indiana
after 1 May: willc@tektronix
∂21-Apr-85 1444 @MIT-MC:rhh@MIT-VAX reactions to Will's updates
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Apr 85 14:44:02 PST
Received: from MIT-VAX by MIT-MC via Chaosnet; 21 APR 85 17:44:14 EST
Received: by mit-vax.Mit-chaos.Arpa (4.12/4.8) id AA03260; Sun, 21 Apr 85 17:43:51 est
Date: Sun, 21 Apr 85 17:43:51 est
From: Bert Halstead <rhh@mit-vax>
To: scheme@mc
Subject: reactions to Will's updates
unhash-object sounds like a bad idea. In Will's scenario, if an object
(0 . 0) is passed to hash-object, and, say, 77 is returned, subsequent
calls to (unhash-object 77) must return either (0 . 0) or #!false
(presumably the latter is an out if the (0 . 0) has been garbage-
collected). This implies that 77 can NEVER be reused as the hash
code for some other object passed to hash-object! It also implies
(do we want this?) that hash-object is a one-to-one function -- it
is never permissible for more than one object to map to the same hash
code. This is not necessary if hash-object is just a way to compute
an index into some user-maintained hash table, where objects could
be associated with whatever information is desired.
re numbers: Is anything substantial gained by disallowing explicit
"+" signs on the exponents of numbers in scientific notation? -Bert
∂21-Apr-85 1923 @MIT-MC:JINX@MIT-OZ lexical syntax for numbers
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Apr 85 19:22:56 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 21 APR 85 22:22:06 EST
Date: 21 Apr 1985 22:20 EST (Sun)
Message-ID: <JINX.12105060042.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Will Clinger <willc%indiana.csnet@CSNET-RELAY.ARPA>
Cc: scheme@MIT-MC.ARPA
Subject: lexical syntax for numbers
In-reply-to: Msg of 20 Apr 1985 15:33-EST from Will Clinger <willc%indiana.csnet at csnet-relay.arpa>
Two comments:
Why can't exponents have + signs, and why must they be decimal? It
seems to me that they should be any valid representation of an
integer, though they may always want to be exact.
Why don't we fix the order of the exactness, radix, and precision
modifiers? I don't think anything is gained from allowing arbitrary
order and the parser may become simpler if it can easily default.
∂21-Apr-85 1927 @MIT-MC:JINX@MIT-OZ reactions to Will's updates
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Apr 85 19:27:08 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 21 APR 85 22:25:23 EST
Date: 21 Apr 1985 22:24 EST (Sun)
Message-ID: <JINX.12105060636.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Bert Halstead <rhh%MIT-VAX@MIT-MC.ARPA>
Cc: scheme@MIT-MC
Subject: reactions to Will's updates
In-reply-to: Msg of 21 Apr 1985 17:43-EST from Bert Halstead <rhh at mit-vax>
Instead of hash-object and unhash-object, why don't we include
populations? The implementation can be done in terms of hash and
unhash object or more primitively, and they seem to constitute the
most common use of these procedures.
∂21-Apr-85 1929 @MIT-MC:CPH@MIT-OZ lexical syntax for numbers
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Apr 85 19:29:47 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 21 APR 85 22:29:25 EST
Date: Sun, 21 Apr 1985 22:28 EST
Message-ID: <CPH.12105061355.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
Cc: Scheme@MIT-MC.ARPA
Subject: lexical syntax for numbers
In-reply-to: Msg of 21 Apr 1985 22:20-EST from Bill Rozas <JINX>
Date: Sunday, 21 April 1985 22:20-EST
From: Bill Rozas <JINX>
Why don't we fix the order of the exactness, radix, and precision
modifiers? I don't think anything is gained from allowing arbitrary
order and the parser may become simpler if it can easily default.
One thing that is gained from arbitrary order is that one need not
remember what the particular order is -- a great advantage to people
who don't remember trivial details very well and don't like reading
manuals.
∂21-Apr-85 1931 @MIT-MC:CPH@MIT-OZ reactions to Will's updates
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Apr 85 19:31:29 PST
Received: from MIT-OZ by MIT-MC via Chaosnet; 21 APR 85 22:31:16 EST
Date: Sun, 21 Apr 1985 22:29 EST
Message-ID: <CPH.12105061716.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
Cc: Bert Halstead <rhh%MIT-VAX@MIT-MC.ARPA>, scheme@MIT-MC
Subject: reactions to Will's updates
In-reply-to: Msg of 21 Apr 1985 22:24-EST from Bill Rozas <JINX>
Date: Sunday, 21 April 1985 22:24-EST
From: Bill Rozas <JINX>
Instead of hash-object and unhash-object, why don't we include
populations? The implementation can be done in terms of hash and
unhash object or more primitively, and they seem to constitute the
most common use of these procedures.
Actually, the major reason that we implemented hashing is to have
generalized two dimensional property tables, for generic operations.
∂22-Apr-85 1103 JAR@MIT-MC hashing
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Apr 85 11:03:43 PST
Date: Mon, 22 Apr 85 13:40:27 EST
From: Jonathan A Rees <JAR@MIT-MC>
Subject: hashing
To: rhh@MIT-VAX
cc: SCHEME@MIT-MC
In-reply-to: Msg of Sun 21 Apr 85 17:43:51 est from Bert Halstead <rhh at mit-vax>
Message-ID: <[MIT-MC].464776.850422.JAR>
Date: Sun, 21 Apr 85 17:43:51 est
From: Bert Halstead <rhh at mit-vax>
... This implies that 77 can NEVER be reused as the hash
code for some other object passed to hash-object!
This is an intentional feature of the proposal; if recycling is
permitted then the facility takes on a totally different character and
has more liimted application.
Feature:
Non-re-use means that OBJECT-UNHASH, which is desirable for many
applications of these things (like post-GC automatic file closing, weak
tables, and populations), is possible and meaningful.
Antifeatures:
(1) Non-re-use means that OBJECT-HASH is different from Maclisp MAKNUM,
and is therefore, presumably, more expensive.
(2) Non-re-use means that in very-long-lived systems, hash numbers might
go into bignums.
---
The hash/unhash facility is already optional, and I would suggest that
if for some reason you don't like its details you can just not implement
it.
If there is much disagreement now about the facility, then it should be
removed from the report. This removal should be done carefully, since
we agreed on it last fall, and agreements are precious; a different hash
facility probably won't make it into the report.
Jonathan
∂22-Apr-85 1117 JAR@MIT-MC hashing
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Apr 85 11:17:40 PST
Date: Mon, 22 Apr 85 14:12:52 EST
From: Jonathan A Rees <JAR@MIT-MC>
Subject: hashing
To: JINX@MIT-OZ
cc: SCHEME@MIT-MC, rhh@MIT-VAX
In-reply-to: Msg of 21 Apr 1985 22:24 EST (Sun) from Bill Rozas <JINX%MIT-OZ at MIT-MC.ARPA>
Message-ID: <[MIT-MC].464817.850422.JAR>
Date: 21 Apr 1985 22:24 EST (Sun)
From: Bill Rozas <JINX%MIT-OZ at MIT-MC.ARPA>
Instead of hash-object and unhash-object, why don't we include
populations? The implementation can be done in terms of hash and
unhash object or more primitively, and they seem to constitute the
most common use of these procedures.
I don't think populations are much easier to implement than hash/unhash,
and they aren't as general. T started out having populations, and a
year or two later acquired OBJECT-HASH, which was applicable in many
situations where populations wouldn't do. (I think you might be able
to implement hash/unhash in terms of populations, but it's much less
natural than vice versa.)
Uses for hash/unhash include populations, weak tables, and file closing,
as well as the following interesting hack, which has tremendous
popularity with users: PRINT calls OBJECT-HASH when it comes across an
object with no standard external representation, a procedure for
example, and prints the hash number along with any other type and
identification info it can find: e.g.
> cadr ;User's typein
#{Procedure 31 CADR} ;System's typeout
> (lambda (x) (* x 3))
#{Procedure 32}
>
Although the syntax #{...} isn't readable (that could cause very bizarre
results for READ's done in processes different from the one which
printed the object), you can evaluate (OBJECT-UNHASH 32) and, if the
garbage collector hasn't done away with it, get the procedure back.
This is vaguely like "D-lines" in Macsyma, except that it permits
reclamation.
Note that hash is called only when PRINT is called, so there is no
evaluator overhead involved. (One user was at first baffled by the
following interaction:
> (lambda () 1)
#{Procedure 33}
> (lambda () 2)
#{Procedure 34}
> (do ((i 0 (1+ i))
(p nil (lambda () i)))
((= i 100) p))
#{Procedure 35}
>
and then figured out that PRINT was generating the numbers.)
∂22-Apr-85 1226 @MIT-MC:wagle%indiana.csnet@csnet-relay.arpa mapcar and mapc
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Apr 85 12:25:45 PST
Received: from csnet-relay by MIT-MC.ARPA; 22 APR 85 15:24:22 EST
Received: from indiana by csnet-relay.csnet id a002853; 22 Apr 85 15:16 EST
Date: Mon, 22 Apr 85 13:54:19 est
From: Perry Wagle <wagle%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA17597; Mon, 22 Apr 85 13:54:19 est
To: scheme%indiana.csnet@csnet-relay.arpa
Subject: mapcar and mapc
In response to Will Clinger's acceptance of the "mapc" -> "for-each"
renaming:
How about renaming "mapc" to "mapcar!" (and thence to "map!")?
This would change the meaning of the bang notation from "Hi! I'm a
side-effecting function" to "Hi! I'm expecting either myself or one of the
functions that I call to be a side-effecting function".
This way, the two very simular functions "map" and "map!" keep simular
names, making life easier on the frail memory of the user.
Perry Wagle
∂22-Apr-85 1302 @MIT-MC:rhh@MIT-VAX Re: hashing
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Apr 85 13:02:29 PST
Received: from MIT-VAX by MIT-MC via Chaosnet; 22 APR 85 16:02:23 EST
Received: by mit-vax.Mit-chaos.Arpa (4.12/4.8) id AA08654; Mon, 22 Apr 85 16:02:07 est
Date: Mon, 22 Apr 85 16:02:07 est
From: Bert Halstead <rhh@mit-vax>
To: JAR@MIT-MC
Subject: Re: hashing
Cc: SCHEME@MIT-MC
Roger, I'm sensitive to the practical issues you raise, as to the mechanics
of getting agreement on the Scheme report. I don't object to object-hash
and object-unhash as optional Scheme functions -- I was just flaming about
implementation considerations which, if they had occurred to me during the
workshop, I had long since forgotten about. It does seem like the issues
of long-lived systems, and the cost of maintaining a hash space that is
ultimately sparsely populated, provide some food for thought. But that's
one thing that optional features are for. -b.
∂22-Apr-85 1544 @MIT-MC:linus!ramsdell@mitre-bedford Two armed IF is essential.
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Apr 85 15:44:28 PST
Received: from mitre-bedford by MIT-MC.ARPA; 22 APR 85 18:43:53 EST
Date: 22 Apr 1985 18:36:48-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA11664; Mon, 22 Apr 85 09:57:17 est
Date: Mon, 22 Apr 85 09:57:17 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8504221457.AA11664@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: Two armed IF is essential.
>>>From bccvax!willc%indiana.csnet@csnet-relay.arpa Sun Apr 21 14:30:50 1985
>>>...
>>>Two-armed if will change from essential to optional status.
One-armed IF may change from essential to optional status,
but please don't change two-armed IF.
John
∂22-Apr-85 1547 @MIT-MC:linus!ramsdell@mitre-bedford REC => LABEL
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Apr 85 15:46:59 PST
Received: from mitre-bedford by MIT-MC.ARPA; 22 APR 85 18:44:29 EST
Date: 22 Apr 1985 18:36:55-EST
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA12343; Mon, 22 Apr 85 10:34:00 est
Date: Mon, 22 Apr 85 10:34:00 est
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8504221534.AA12343@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: REC => LABEL
I know its too late, but I support Mitch Wand's
suggested rename for REC.
John
∂23-Apr-85 0912 @MIT-MC:wagle%indiana.csnet@csnet-relay.arpa Retraction and Resubmission
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 23 Apr 85 09:11:58 PST
Received: from csnet-relay by MIT-MC.ARPA; 23 APR 85 11:58:20 EST
Received: from indiana by csnet-relay.csnet id ad08662; 23 Apr 85 11:52 EST
Date: Tue, 23 Apr 85 11:12:36 est
From: Perry Wagle <wagle%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA11641; Tue, 23 Apr 85 11:12:36 est
To: scheme%indiana.csnet@csnet-relay.arpa
Subject: Retraction and Resubmission
I noticed later that my suggestion about the renaming of "mapc" is
somewhat bogus, I apologize:
Mapcar-type functions have two primary operating parameters: (1) the order
in which the list is processed, (2) a resultant value from whether the list
is copied, side-effected, or forgotten.
The current "mapcar" processes in arbitrary order and returns the copied
list. The current "mapc" processes in left-to-right order and forgets the
list (returning nothing). Quite, ahem, different.
(The most direct interpretation of a function named "mapcar!" would be one
that set-car!ed the list, returned the side-effected list, and was open as
to whether to process in arbitrary or left-to-right order.)
I would have use for (in order of frequency):
(1) arb-order, copy list, return list. (the current mapcar).
(2) LR-order, copy list, return list. I don't like set-car!ing cons-cells,
but I make much use of files and continuations, so order matters a lot.
(3) LR-order, forget list, return nothing. (the current mapc). Print lists.
(4) LR-order, side-effect list, return list. If keeping same cons-cell is
important for some reason.
Perhaps only a subset of the set of useful mapcar variations should be
provided by the system - the two that already are? The points would still
remain of denoting their status as a member of this grouping by using the
word "map" in the name, of having special marking for functions that
guarantee left-to-right evaluation or processing, and having a naming
convention for the others should they ever be realized.
My suggestion is to distinguish between the arbitrary and left-to-right
list processing but starting off with two roots "map" and "map/lr",
respectively. Futhermore, since there are three values returned - a copied
list, a set-car!ed list, and nothing at all - "copy", "list!", and "" (null),
respectively. Then the four hypothetical functions above would be named:
(1) "map->copy"
(2) "map/lr->copy"
(3) "map/lr"
(4) "map/lr->list!" or "map/lr->same!" or ... (?)
(Note that while there would be no reasonable value for (a fifth) "map" to
return, while "map/lr" could return the value of the last mapping.)
Perry Wagle
∂23-Apr-85 1336 JAR@MIT-MC Two armed IF is essential.
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 23 Apr 85 13:36:20 PST
Date: Tue, 23 Apr 85 16:25:21 EST
From: Jonathan A Rees <JAR@MIT-MC>
Subject: Two armed IF is essential.
To: SCHEME@MIT-MC, linus!ramsdell@MITRE-BEDFORD
In-reply-to: Msg of 22 Apr 1985 18:36:48-EST
Mon 22 Apr 85 09:57:17 est from linus!ramsdell at Mitre-Bedford,
linus!ramsdell (John D. Ramsdell) at Mitre-Bedford
Message-ID: <[MIT-MC].466615.850423.JAR>
Date: 22 Apr 1985 18:36:48-EST
From: linus!ramsdell at Mitre-Bedford
One-armed IF may change from essential to optional status,
but please don't change two-armed IF.
I think this was what Will intended to write. The terminology is
confusing, since an IF with N arms has N+1 subforms, and he probably
wrote arm and meant subform.
So: (IF test consequent alternate) essential
(IF test consequent) optional
Jonathan
∂24-Apr-85 1541 @MIT-MC:willc%indiana.csnet@csnet-relay.arpa two-armed if (oops)
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 24 Apr 85 15:41:40 PST
Received: from csnet-relay by MIT-MC.ARPA; 24 APR 85 18:41:59 EST
Received: from indiana by csnet-relay.csnet id ad16863; 24 Apr 85 14:38 EST
Date: Wed, 24 Apr 85 12:48:17 est
From: Will Clinger <willc%indiana.csnet@csnet-relay.arpa>
Received: by iuvax.UUCP; id AA05047; Wed, 24 Apr 85 12:48:17 est
To: scheme@mit-mc.ARPA
Subject: two-armed if (oops)
Yikes! Thank you John, I meant to say that ONE-ARMED IF would become
optional. TWO-ARMED IF will remain essential, of course.
There has already been sufficient response to convince me that plus signs
should be allowed in exponents.
Still at issue is whether exponents can have radix, precision, or exactness
specifiers, and indeed whether exponents should be allowed to have arbitrary
number syntax. At some point the more general exponent syntax should become
extended rather than optional, and all we're trying to do is to determine
that point.
Peace, William
∂25-Apr-85 0902 @MIT-MC:rhh@MIT-VAX number exponent syntax
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 25 Apr 85 09:01:49 PST
Received: from MIT-VAX by MIT-MC via Chaosnet; 25 APR 85 12:03:03 EST
Received: by mit-vax.Mit-chaos.Arpa (4.12/4.8) id AA05298; Thu, 25 Apr 85 12:01:58 est
Date: Thu, 25 Apr 85 12:01:58 est
From: Bert Halstead <rhh@mit-vax>
To: scheme@mit-mc.ARPA, willc%indiana.csnet@csnet-relay.arpa
Subject: number exponent syntax
Seems to me that precision and exactness are (almost) completely
meaningless in an exponent. One could perhaps make an argument for
different radices in the exponent notation, but then one could also
make an argument for other things (e.g., scientific notation with
a base other than 10). I'd probably just as soon we didn't. -Bert
∂26-Apr-85 0037 JAR@MIT-MC number exponent syntax
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Apr 85 00:36:50 PST
Date: Thu, 25 Apr 85 15:42:31 EST
From: Jonathan A Rees <JAR@MIT-MC>
Subject: number exponent syntax
To: rhh@MIT-VAX
cc: SCHEME@MIT-MC
In-reply-to: Msg of Thu 25 Apr 85 12:01:58 est from Bert Halstead <rhh at mit-vax>
Message-ID: <[MIT-MC].469882.850425.JAR>
Date: Thu, 25 Apr 85 12:01:58 est
From: Bert Halstead <rhh at mit-vax>
Seems to me that precision and exactness are (almost) completely
meaningless in an exponent. One could perhaps make an argument for
different radices in the exponent notation, but then one could also
make an argument for other things (e.g., scientific notation with
a base other than 10). I'd probably just as soon we didn't.
I'm not one to talk, since I never use numbers, but I read a CACM
article once about a proposed hardware number representation in which
one could represent numbers with no significant digits in their
EXPONENT. The author claimed that this was useful. So not all of
this meaninglessness is to be concluded forgonely.
Don't take this as a contrary argument; merely a word of caution.
Jonathan
∂26-Apr-85 0351 @MIT-MC:rhh@MIT-VAX Re: number exponent syntax
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Apr 85 03:51:03 PST
Received: from MIT-VAX by MIT-MC via Chaosnet; 25 APR 85 16:08:56 EST
Received: by mit-vax.Mit-chaos.Arpa (4.12/4.8) id AA09287; Thu, 25 Apr 85 16:07:44 est
Date: Thu, 25 Apr 85 16:07:44 est
From: Bert Halstead <rhh@mit-vax>
To: JAR@MIT-MC
Subject: Re: number exponent syntax
Cc: SCHEME@mc
Yeah, I saw the same article, and it was the thought of that that caused
me to insert the words "(almost)" in my message. But once we start
having impreciseness in our exponent, there is little point to saying
anything about the mantissa! I figured this was probably a minefield
Scheme could avoid entering. -Bert
∂21-Jun-85 1631 @MIT-MC.ARPA:willc%tekchips%tektronix.csnet@csnet-relay.arpa lcm
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Jun 85 16:31:10 PDT
Received: from csnet-relay by MIT-MC.ARPA 21 Jun 85 19:31:11 EST
Received: from tektronix by csnet-relay.csnet id ac01342; 21 Jun 85 18:43 EDT
From: Will Clinger <willc%tekchips%tektronix.csnet@csnet-relay.arpa>
To: scheme@MIT-MC.ARPA
Received: from tekchips by tektronix with smtp ; 21 Jun 85 11:30:56 PDT
Date: Friday, 21 Jun 85 11:25:37 PDT
Subject: lcm
A question from John Gateley (gateley%waltz@ti-csl.csnet) and my response:
Gateley:
Common lisp says (lcm) = infinity, and since they don't have
a representation of infinity, lcm is required to have at least
one argument. Scheme says (lcm) = 1. Also, common lisp allows lcm to
take 0 as an argument, with result 0. Scheme does not allow zero as
an argument. Is this what is desired, or should scheme be closer to
common lisp.
Clinger:
The relevant passage in Guy Steele's book is on page 202:
"Mathematically, (lcm) should return infinity. Because Common Lisp
does not have a representation for infinity, lcm, unlike gcd, always
requires at least one argument."
Even as a mathematician, I can't agree that (lcm) should return infinity,
because the n-ary generalization of an associative binary operator should
return an identity for the operator when it is given no arguments. Infinity
certainly isn't an identity for lcm. 1 is.
I think I inserted the requirement that the arguments to lcm be non-zero. I
have no particular quarrel with Common Lisp on this matter, but I didn't want
to get bogged down in pathological cases. Since it is inconsistent to allow
zero as an argument to gcd but not to lcm, I would like to change the report so
that lcm behaves as in Common Lisp when given a zero argument.
∂21-Jun-85 1723 @MIT-MC.ARPA:ANDY@SU-SUSHI.ARPA Re: lcm
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 21 Jun 85 17:23:16 PDT
Received: from SU-SUSHI.ARPA by MIT-MC.ARPA 21 Jun 85 20:22:54 EST
Date: Fri 21 Jun 85 17:22:22-PDT
From: Andy Freeman <ANDY@SU-SUSHI.ARPA>
Subject: Re: lcm
To: willc%tekchips%tektronix.csnet@CSNET-RELAY.ARPA
cc: scheme@MIT-MC.ARPA
In-Reply-To: Message from "Will Clinger <willc%tekchips%tektronix.csnet@csnet-relay.arpa>" of Fri 21 Jun 85 16:37:59-PDT
(lcm) recently came up on the common lisp mailing list and that the
decision was that the Common Lisp manual was wrong. I believe Bill
Gosper and Alan Bawden were major participants in that discussion.
I'd review that before making a decision.
-andy
-------
∂09-Jul-85 2145 @MIT-MC.ARPA:ALTMAN%ti-csl.csnet@csnet-relay.arpa Scheme Benchmark Programs Sought
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Jul 85 21:45:03 PDT
Received: from csnet-relay by MIT-MC.ARPA.ARPA; 10 Jul 85 00:39:55 EDT
Received: from ti-csl by csnet-relay.csnet id aj16083; 10 Jul 85 0:30 EDT
Date: 9 Jul 1985 0937-CDT
From: Arthur <Altman%CSL60%ti-csl.csnet@csnet-relay.arpa>
Subject: Scheme Benchmark Programs Sought
To: scheme@mit-mc.ARPA
cc: scheme.users%CSL60%ti-csl.csnet@csnet-relay.arpa
Received: from csl60 by ti-csl; Tue, 9 Jul 85 21:10 CST
Hello, Un-Common Lisp Lovers:
I am beginning a Scheme performance evaluation project here at TI CSL,
an initial task being to build a suite of benchmark programs. Beyond the
Gabriel Lisp Benchmark Suite translated to Scheme and examples from A&S,
most Scheme programs around these days seem to be "systems" code, e.g.,
compilers and editors.
I am soliciting "applications" code from Scheme users, especially
programs that show off **canonical Scheme programming style**. I am not
placing any limits a priori on the code size, however, I do request that
source provided conforms to the Revised Revised Report.
What's in it for you? Well, possible enshrinement of your name and all
or part of your favorite program in a "standard" benchmark suite for
Scheme. Also, the good feeling that comes with advancing the cause of
Lisp-Done-Right, since I hope to show off the performance advantages of
the Scheme runtime model.
The ultimate suite of programs will be made available over the net to
interested parties, of course. Thanks for your cooperation.
Regards,
Arthur Altman
Texas Instruments
Computer Science Laboratory
(214) 995-0383
CSNET: altman@ti-csl
ARPANET: altman%ti-csl@csnet-relay
U.S. Postal Service: M.S. 238, P.O. Box 226015, Dallas, Texas, 75266
-------
∂09-Jul-85 2325 @MIT-MC.ARPA:mw%brandeis.csnet@csnet-relay.arpa What cr*p
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Jul 85 23:24:55 PDT
Received: from csnet-relay by MIT-MC.ARPA.ARPA; 10 Jul 85 02:26:14 EDT
Received: from brandeis by csnet-relay.csnet id a016623; 10 Jul 85 2:18 EDT
Received: by brandeis.ARPA (4.12/4.7)
id AA08833; Tue, 9 Jul 85 22:33:50 edt
Date: 9 Jul 1985 22:27-EST
From: mw%brandeis.csnet@csnet-relay.arpa
In-Real-Life: Mitchell Wand,faculty
Subject: What cr*p
To: dpf%indiana.csnet@csnet-relay.arpa,
lang-scheme%indiana.csnet@csnet-relay.arpa,
cth%indiana.csnet@csnet-relay.arpa, scheme@mit-mc.ARPA
Message-Id: <489810451/mw@brandeis>
Would you believe that Software: Practice & Experience is about to
publish a paper entitled "On the role of t and nil in Lisp", and whose
abstract is "It is widely believed that McCarthy's interpreter is a
running Lisp program. It is not, because it does not interpret t and
nil correctly. We show how to fix this bug." It's only 2-1/2 pages,
but MUMBLE!
∂11-Jul-85 2016 GJC@MIT-MC.ARPA What cr*p
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 11 Jul 85 20:16:18 PDT
Date: Thu, 11 Jul 85 23:17:53 EDT
From: George J. Carrette <GJC@MIT-MC.ARPA>
Subject: What cr*p
To: mw%brandeis.csnet@CSNET-RELAY.ARPA
cc: SCHEME@MIT-MC.ARPA, cth%indiana.csnet@CSNET-RELAY.ARPA,
dpf%indiana.csnet@CSNET-RELAY.ARPA,
lang-scheme%indiana.csnet@CSNET-RELAY.ARPA
In-reply-to: Msg of 9 Jul 1985 22:27-EST from mw%brandeis.csnet at csnet-relay.arpa
Message-ID: <[MIT-MC.ARPA].572724.850711.GJC>
If you think *thats* bad... a paper on a reference count garbage
collection technique in the ISA conference on expert systems
and robotics this June.
And if you think thats bad you should see the kind of proposals
DOD is getting for "supercomputer lispmachines"
∂19-Jul-85 1756 @MIT-MC.ARPA:linus!ramsdell@mitre-bedford CSI Lisp is not tail recursive
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 19 Jul 85 17:55:52 PDT
Received: from mitre-bedford by MIT-MC.ARPA 19 Jul 85 20:56:49 EDT
Date: 19 Jul 1985 20:51:17-EDT
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA25878; Fri, 19 Jul 85 09:48:40 edt
Date: Fri, 19 Jul 85 09:48:40 edt
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8507191348.AA25878@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: CSI Lisp is not tail recursive
An advertisement for CSI Lisp recently appeared in CACM.
The ad states "CSI LISP is a new implementation of T,
which is decended from SCHEME". For those who don't know,
T is a dialect of SCHEME that is fairly true to SCHEME's
basic ideas. For example, T programmers are allowed to
assume that evaluation of programs is tail recursive.
Looping constructs generated out of tail recursive
procedures do not increase the size of the stack.
Recent mail to T-DISCUSSION@YALE reveal that CSI Lisp
makes no promise to be tail recursive and is not tail
recursive on implementations that run on top of
Common Lisp and LISP-VM! I believe Cognitive Systems
must reveal that CSI Lisp is not tail recursive or
it should not associate CSI Lisp with T and SCHEME
in its ads.
In my opinion, a language should, at the very least,
be tail recursive if it is to be associated with SCHEME.
John
PS Ada's name is protected - can anything be done for
SCHEME's name?
∂20-Jul-85 0350 GJC@MIT-MC.ARPA truth in advertisement
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 20 Jul 85 03:50:10 PDT
Date: Sat, 20 Jul 85 06:51:14 EDT
From: George J. Carrette <GJC@MIT-MC.ARPA>
Subject: truth in advertisement
To: SCHEME@MIT-MC.ARPA, linus!ramsdell@MITRE-BEDFORD.ARPA
In-reply-to: Msg of 19 Jul 1985 20:51:17-EDT
Fri 19 Jul 85 09:48:40 edt from linus!ramsdell at Mitre-Bedford,
linus!ramsdell (John D. Ramsdell) at Mitre-Bedford
Message-ID: <[MIT-MC.ARPA].582540.850720.GJC>
I think that just about all one can do is send letters to the editors
of the magazines publishing such advertisements. Another thing one can
do is write a letter to the company asking "will your product run the
enclosed program: X" to which they will probably reply yes (because it
will on one implementation). Then you write a letter saying, "great,
here is my $$$ please send me a copy." Then when you get the bogus
copy that wont run your program you say to them: "Please send my money
back." To make it most effective you get 10 or 20 people in on this
doing exactly the same thing. The company wont be as willing to give
back thousands of dollars. Then when they dont give the money back you
go to the Atterny (spell program no help for this word) General's
Office and file a complaint (both state and federal). 10 to 20
complaints are enough to get the feds moving on a
mail-fraud/wire-fraud investigation. The laws protecting consumers
from magazine advertisement mail-order rip-offs are sufficiently
strong to cause server problems to a company in arrears. For one
thing just the act of filing so many complaints can make it
difficult for a small company to raise money from sources that
are smart enough to check for such things. And if things get serious
enough the post office can cut off their mail (quite a screw eh?),
not to mention the criminal penalties that hang over them.
On the other hand, given the effort of making an example of
a company like this, and given how much work it is to do a reasonable
Scheme implementation on top of any halfway decent lisp,
maybe it would be better for us to pitch in and come up with
and advertise for distribution-at-cost some true Scheme implementation?
It would probably be less work (although maybe less fun) than screwing
some losing company to the wall.
-gjc
∂22-Jul-85 1043 @MIT-MC.ARPA:gls@THINK-AQUINAS.ARPA truth in advertisement
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Jul 85 10:43:49 PDT
Received: from THINK.ARPA by MIT-MC.ARPA 22 Jul 85 13:42:58 EDT
Received: by THINK.ARPA with CHAOS; Mon, 22 Jul 85 13:39:45 edt
Date: Mon, 22 Jul 85 13:41 EDT
From: Guy Steele <gls@THINK-AQUINAS.ARPA>
Subject: truth in advertisement
To: GJC@MIT-MC.ARPA, SCHEME@MIT-MC.ARPA, linus!ramsdell@MITRE-BEDFORD.ARPA
Cc: gls@THINK-AQUINAS.ARPA
In-Reply-To: <[MIT-MC.ARPA].582540.850720.GJC>
Message-Id: <850722134121.2.GLS@UBALDO.ARPA>
Well, if you believe that the company is truly sinister and trying to
rip people off with shoddy merchandise, then all the legal apparatus
that GJC describes may be brought to bear. But it may be that the lack
of tail-recursion is due to incompetence, ignorance, oversight, or maybe
even an intentional tradeoff made to gain something else. There is a
lot to be said for first writing or calling the company and reporting it
as a bug and politely asking how soon it will be fixed. What you do
next depends on their reaction.
--Guy
∂22-Jul-85 1522 GJC@MIT-MC.ARPA truth in advertisement
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 22 Jul 85 15:22:45 PDT
Date: Mon, 22 Jul 85 18:23:54 EDT
From: George J. Carrette <GJC@MIT-MC.ARPA>
Subject: truth in advertisement
To: gls@THINK-AQUINAS.ARPA
cc: SCHEME@MIT-MC.ARPA, linus!ramsdell@MITRE-BEDFORD.ARPA
In-reply-to: Msg of Mon 22 Jul 85 13:41 EDT from Guy Steele <gls at THINK-AQUINAS.ARPA>
Message-ID: <[MIT-MC.ARPA].584702.850722.GJC>
I just saw the price of the thing, $10K for the DEC/VAXLISP version.
Now considering the DEC/VAXLISP cost is $12k, charging $10K
for a three or four page lisp program that does syntactic
translation of Scheme code into Common-Lisp code is a bit
absurd. The question is what has been written in "T" that
has that kind of economic value? Evidently a few things!
Or it could be the case of Unix costing $300 from Berkeley
or a Unix emulator under VMS costing you a minimum of $8k.
∂24-Jul-85 1622 @MIT-MC.ARPA:linus!ramsdell@mitre-bedford
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 24 Jul 85 16:22:09 PDT
Received: from mitre-bedford by MIT-MC.ARPA 24 Jul 85 19:20:04 EDT
Date: 24 Jul 1985 17:35:50-EDT
From: linus!ramsdell@Mitre-Bedford
Received: by linus.UUCP (4.12/4.7)
id AA16213; Wed, 24 Jul 85 08:00:35 edt
Date: Wed, 24 Jul 85 08:00:35 edt
From: linus!ramsdell (John D. Ramsdell)
Message-Id: <8507241200.AA16213@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Received: by linus.UUCP (4.12/4.7)
id AA07000; Tue, 23 Jul 85 07:57:28 edt
Date: Tue, 23 Jul 85 07:57:28 edt
From: ramsdell (John D. Ramsdell)
Message-Id: <8507231157.AA07000@linus.UUCP>
To: bccvax!scheme@mit-mc.arpa
Subject: CSI Lisp
Cc: bccvax!meehan@yale
In my opinion, CSI Lisp was implemented by knowledgeable
people who know very well about tail recursion optimization.
They are not the kind of people that would leave it out
because its too hard to figure out. In fact, their Apollo
implementation reliably does the optimization. They left
it out from some implementations because they wanted to port
their programs to machines by implementing their lisp on top
of existing systems. Since Common Lisp and Lisp-VM are not
required to do the opimization, they realized that they would
incure much pain and suffering if they spend the effort to
get it right in these lisps. Reasonable people doing
reasonable things. My only complaint is that reasonable
people reading their ad in CACM would conclude that all their
implementations are tail recursive.
Cognitive Systems should be applauded for porting a dialect
of lisp that is much simpler than Common Lisp, yet just as
useful. I think it is important to recognise the good
with the bad. Comments and questions about CSI Lisp
should be directed to Jim Meehan (MEEHAN@YALE).
John
∂24-Jul-85 1929 @MIT-MC.ARPA:OXLEY%ti-csl.csnet@csnet-relay.arpa Scheme Not Tail Recursive!!!????
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 24 Jul 85 19:26:06 PDT
Received: from csnet-relay by MIT-MC.ARPA 24 Jul 85 22:26:05 EDT
Received: from ti-csl by csnet-relay.csnet id ac16288; 24 Jul 85 7:55 EDT
Date: 23 Jul 1985 1602-CDT
From: Don Oxley <OXLEY%CSL60%ti-csl.csnet@csnet-relay.arpa>
Subject: Scheme Not Tail Recursive!!!????
To: Willc%tekchips%tektronix.csnet@csnet-relay.arpa
cc: Scheme@mit-mc.ARPA
Received: from csl60 by ti-csl; Wed, 24 Jul 85 00:53 CST
In reading the revised, revised report, I can find no statement - either
direct or inferred, that Scheme is required to be properly tail
recursive.
Did I overlook something?
I suggest a requirement to that effect be inserted (as an errata if
necessary) on page 8.
A much more picky point. On page 7, is the statement that ALL objects
have unlimited extent. Since fluid variables have dynamic extent, it
seems to me that a picky interpretation could preclude fluid variables
in the language (the counter argument of course is that is a sufficient
base to implement fluids). Would a bit of clarification be helpful?
--Don
PS. Sorry for nitpicking AFTER the report is out, but sometimes you
have to be writing your own manual to be able to read another carefully.
-------
∂24-Jul-85 1944 @MIT-MC.ARPA:willc%tekchips%tektronix.csnet@csnet-relay.arpa Re: Scheme Not Tail Recursive!!!????
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 24 Jul 85 19:43:51 PDT
Received: from csnet-relay by MIT-MC.ARPA 24 Jul 85 22:44:31 EDT
Received: from tektronix by csnet-relay.csnet id ac20001; 24 Jul 85 21:42 EDT
From: Will Clinger <willc%tekchips%tektronix.csnet@csnet-relay.arpa>
To: oxley%ti-csl.csnet@csnet-relay.arpa
Cc: scheme@MIT-MC.ARPA
Received: from tekchips by tektronix with smtp ; 24 Jul 85 17:47:51 PDT
Date: Wednesday, 24 Jul 85 17:33:05 PDT
Subject: Re: Scheme Not Tail Recursive!!!????
In-reply-to: Your message of 23 Jul 1985 1602-CDT.
Finite Memories Considered Harmful (same song, second verse)
Tail recursion is an implementation issue rather than a matter of
semantics. Gedanken experiment: the Incredibly Big Machine
Corporation decides that it can increase its profits by compiling
tail recursion improperly while bundling its machines with a contract
that calls for customers to add 10↑13 bytes of RAM each month as part
of preventive maintenance.
Likewise garbage collection is an implementation issue, not a matter
of semantics. There's nothing in the Revised Revised Report to
mandate a garbage collector.
On the other hand: Anything that causes programs to run out of
memory is a bug.
It may be that the Incredibly Big Machine Corporation is shipping a
bug-free product. That cannot be said for any implementation that
uses a finite memory.
It is philosophically inconsistent to insist upon proper treatment of
tail recursion and upon garbage collection while allowing finite
memories. Of course, people know to ask about the finite memory bug
when they purchase a computer. Indeed, the bug is often advertised.
Not so many people know to ask about tail recursion and garbage
collectors, so maybe we should be inconsistent.
William Clinger
∂25-Jul-85 0342 @MIT-MC.ARPA:GJS@MIT-OZ Re: Scheme Not Tail Recursive!!!????
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 25 Jul 85 03:39:15 PDT
Received: from MIT-OZ by MIT-MC.ARPA via Chaosnet; 25 JUL 85 06:39:15 EDT
Date: Thu 25 Jul 85 06:39:18-EDT
From: Gerald Jay Sussman <GJS%MIT-OZ@MIT-MC.ARPA>
Subject: Re: Scheme Not Tail Recursive!!!????
To: willc%tekchips%tektronix.csnet@CSNET-RELAY.ARPA
cc: oxley%ti-csl.csnet@CSNET-RELAY.ARPA, scheme@MIT-MC.ARPA
In-Reply-To: Message from "Will Clinger <willc%tekchips%tektronix.csnet@csnet-relay.arpa>" of Wed 24 Jul 85 22:47:15-EDT
Unless anyone objects, I will insert a one-liner stating that we expect
both tail-recursion and dynamic storage allocation and deallocation are
assumed in any legit implementation (consistent with modern hardware implementations)
-------
∂25-Jul-85 1115 JAR@MIT-MC.ARPA Are fluids objects?
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 25 Jul 85 11:15:22 PDT
Date: Thu, 25 Jul 85 14:16:00 EDT
From: Jonathan A Rees <JAR@MIT-MC.ARPA>
Subject: Are fluids objects?
To: OXLEY%CSL60%ti-csl.csnet@CSNET-RELAY.ARPA
cc: SCHEME@MIT-MC.ARPA,
Willc%tekchips%tektronix.csnet@CSNET-RELAY.ARPA
Message-ID: <[MIT-MC.ARPA].587507.850725.JAR>
Date: 23 Jul 1985 1602-CDT
From: Don Oxley <OXLEY%CSL60%ti-csl.csnet at csnet-relay.arpa>
A much more picky point. On page 7, is the statement that ALL objects
have unlimited extent. Since fluid variables have dynamic extent, it
seems to me that a picky interpretation could preclude fluid variables
in the language (the counter argument of course is that is a sufficient
base to implement fluids). Would a bit of clarification be helpful?
I'm no semantics wiz, but I think that "object" is used consistently in
the Scheme and Lisp literature to mean what corresponds to "expressed
value" in denotational semanticses. Perhaps this point should be made
somewhere. But I believe that if this point is understood, nothing need
be said about fluids, since they are not necessarily objects (expressed
values). Anything at all can have dynamic extent if it pleases, as
long as it is not an object.
On the other hand, I don't think the report should preclude language
extensions, and some of these extensions might include various kinds of
second-class citizens, including perhaps objects with only dynamic
extent. (I don't think I'd do such a thing, but someone else might.)
If other people agree with me on this, maybe some clarification of the
statement on page 7 is in order.
Jonathan
∂25-Jul-85 1125 @MIT-MC.ARPA:JINX@MIT-OZ Scheme Not Tail Recursive!!!????
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 25 Jul 85 11:24:56 PDT
Received: from MIT-OZ by MIT-MC.ARPA via Chaosnet; 25 JUL 85 14:09:08 EDT
Date: 25 Jul 1985 11:49 EDT (Thu)
Message-ID: <JINX.12129837829.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Don Oxley <OXLEY%CSL60%ti-csl.csnet@CSNET-RELAY.ARPA>
Cc: Scheme@MIT-MC.ARPA, Willc%tekchips%tektronix.csnet@CSNET-RELAY.ARPA
Subject: Scheme Not Tail Recursive!!!????
In-reply-to: Msg of 23 Jul 1985 17:02-EDT from Don Oxley <OXLEY%CSL60%ti-csl.csnet at csnet-relay.arpa>
I think we should be fairly harsh about this issue. I don't consider
an implementation which is not properly tail recursive an acceptable
implementation. Note also that by properly tail recursive I don't
mean something which just "optimizes" reduction self-calls, but rather
one that keeps a minimum amount of state on any reduction.
I don't understand your objections about the extent of fluid
variables. I don't think a variable binding is an object, and
certainly in the context of the report there is no way of obtaining it
or manipulating it as an object (so it would not be first class at
least). Not being an object, its extent can be limited. However, the
objects being "dynamically bound" must certainly have unlimited
extent. This difference is similar to the difference between a macro
(whatever that may be), and a macro expander, which is a legitimate
object (probably a procedure). Both variable bindings and macros are
conceptual entities with no counterpart in the language, the objects
bound to and the macro expanders are "real" objects which are subject
to the same contraints as all other objects.
Note also that even if something has formally unlimited extent, if an
implementation can prove that it is no longer accessible it can
recalim its storage. This is what gc is based on, but nobody claims
that any implementation must wait until an actual system-wide gc to
reclaim pieces of storage.
∂25-Jul-85 1310 @MIT-MC.ARPA:JINX@MIT-OZ previous message
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 25 Jul 85 13:09:52 PDT
Received: from MIT-OZ by MIT-MC.ARPA via Chaosnet; 25 JUL 85 16:08:23 EDT
Date: 25 Jul 1985 15:39 EDT (Thu)
Message-ID: <JINX.12129879691.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
Subject: previous message
To: scheme@MIT-MC.ARPA
I apologize for my previous message, the message does not read as I
expected. It was certainly not my intent to to alienate anybody.
∂26-Jul-85 1444 @MIT-MC.ARPA:BARTLEY%ti-csl.csnet@csnet-relay.arpa Re: Scheme Not Tail Recursive!!!????
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Jul 85 14:42:59 PDT
Received: from csnet-relay by MIT-MC.ARPA 26 Jul 85 17:43:23 EDT
Received: from ti-csl by csnet-relay.csnet id ah08928; 26 Jul 85 17:36 EDT
Date: 25 Jul 1985 1055-CDT
From: David Bartley <Bartley%CSL60%ti-csl.csnet@csnet-relay.arpa>
Subject: Re: Scheme Not Tail Recursive!!!????
To: GJS%MIT-OZ@mit-mc.ARPA, willc%tekchips%tektronix.csnet@csnet-relay.arpa
cc: oxley%ti-csl.csnet@csnet-relay.arpa, scheme@mit-mc.ARPA,
Bartley%CSL60%ti-csl.csnet@csnet-relay.arpa
In-Reply-To: Your message of 25-Jul-85 0638-CDT
Received: from csl60 by ti-csl; Thu, 25 Jul 85 13:06 CST
I agree with Don and Gerry. The standard has to take some notice of the
finiteness of machines (why else have INEXACT?). Also, the 1978 revised
report specifically states that "Scheme is implemented in such a way that
tail-recursions execute without net growth of the interpreter stack."
Leaving such a statement out of the revised revised report would seem to
imply that the language has changed in that respect.
-------
∂26-Jul-85 2251 @MIT-MC.ARPA:BARTLEY%ti-csl.csnet@csnet-relay.arpa Ambiguous number syntax
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 26 Jul 85 22:50:57 PDT
Received: from csnet-relay by MIT-MC.ARPA 27 Jul 85 01:51:17 EDT
Received: from ti-csl by csnet-relay.csnet id ae10910; 27 Jul 85 1:46 EDT
Date: 26 Jul 1985 1006-CDT
From: David Bartley <Bartley%CSL60%ti-csl.csnet@csnet-relay.arpa>
Subject: Ambiguous number syntax
To: Scheme@mit-mc.ARPA
cc: Bartley%CSL60%ti-csl.csnet@csnet-relay.arpa,
MMeyer%CSL60%ti-csl.csnet@csnet-relay.arpa
Received: from csl60 by ti-csl; Fri, 26 Jul 85 18:48 CST
(1) The RRReport states on page 48 that <radix16> is denoted by #h or #H,
while stating on page 50 that the prefix for hex values is #X. Since
Common Lisp uses #X for "hexadecimal rational" values, we prefer to believe
that the mention of #H on page 48 is a typographical error. Would anyone
like to argue otherwise?
(2) Is it possible to write a number in base 16 scientific notation? How
is the letter 'e' or 'E' to be interpreted -- as a hex digit or the start
of the exponentiation suffix?
David Bartley,
Mark Meyer
-------
∂27-Jul-85 1715 @MIT-MC.ARPA:GJS@MIT-OZ Re: Ambiguous number syntax
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 27 Jul 85 17:15:17 PDT
Received: from MIT-OZ by MIT-MC.ARPA via Chaosnet; 27 JUL 85 20:15:38 EDT
Date: Sat 27 Jul 85 20:14:38-EDT
From: Gerald Jay Sussman <GJS%MIT-OZ@MIT-MC.ARPA>
Subject: Re: Ambiguous number syntax
To: Bartley%CSL60%ti-csl.csnet@CSNET-RELAY.ARPA
cc: Scheme@MIT-MC.ARPA, MMeyer%CSL60%ti-csl.csnet@CSNET-RELAY.ARPA
In-Reply-To: Message from "David Bartley <Bartley%CSL60%ti-csl.csnet@csnet-relay.arpa>" of Fri 26 Jul 85 11:06:00-EDT
I am doing the last pass now...
(1) The RRReport states on page 48 that <radix16> is denoted by #h or #H,
while stating on page 50 that the prefix for hex values is #X. Since
Common Lisp uses #X for "hexadecimal rational" values, we prefer to believe
that the mention of #H on page 48 is a typographical error. Would anyone
like to argue otherwise?
That was indeed a typo. I will fix it.
(2) Is it possible to write a number in base 16 scientific notation? How
is the letter 'e' or 'E' to be interpreted -- as a hex digit or the start
of the exponentiation suffix?
I don't really have a good idea about that. Perhaps we should defer
any decisions until someone wants to do it! (sounds unlikely). I actually
hate hex and wish it would go away.
-------
∂29-Jul-85 1020 @MIT-MC.ARPA:gls@THINK-AQUINAS.ARPA Re: Ambiguous number syntax
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 29 Jul 85 10:20:23 PDT
Received: from THINK.ARPA by MIT-MC.ARPA 29 Jul 85 13:11:25 EDT
Received: by THINK.ARPA with CHAOS; Mon, 29 Jul 85 13:07:02 edt
Date: Mon, 29 Jul 85 13:06 EDT
From: Guy Steele <gls@THINK-AQUINAS.ARPA>
Subject: Re: Ambiguous number syntax
To: GJS%MIT-OZ@MIT-MC.ARPA, Bartley%CSL60%ti-csl.csnet@CSNET-RELAY.ARPA
Cc: Scheme@MIT-MC.ARPA, MMeyer%CSL60%ti-csl.csnet@CSNET-RELAY.ARPA,
gls@THINK-AQUINAS.ARPA
In-Reply-To: The message of 27 Jul 85 20:14-EDT from Gerald Jay Sussman <GJS%MIT-OZ at MIT-MC>
Message-Id: <850729130650.4.GLS@POLYCARP.ARPA>
Date: Sat 27 Jul 85 20:14:38-EDT
From: Gerald Jay Sussman <GJS%MIT-OZ@MIT-MC.ARPA>
I am doing the last pass now...
(1) The RRReport states on page 48 that <radix16> is denoted by #h or #H,
while stating on page 50 that the prefix for hex values is #X. Since
Common Lisp uses #X for "hexadecimal rational" values, we prefer to believe
that the mention of #H on page 48 is a typographical error. Would anyone
like to argue otherwise?
That was indeed a typo. I will fix it.
(2) Is it possible to write a number in base 16 scientific notation? How
is the letter 'e' or 'E' to be interpreted -- as a hex digit or the start
of the exponentiation suffix?
I don't really have a good idea about that. Perhaps we should defer
any decisions until someone wants to do it! (sounds unlikely). I actually
hate hex and wish it would go away.
-------
I cannot resist passing on one proposal for radix syntax that was
considered for Common Lisp (and rejected, so take it with a grain of
salt!).
First, observe thsat traditional mathematical syntax for a radix is a
trailing subscript:
1000 = 512
8 10
Second, observe that many non-LISP languages uses parentheses or brackets
for subscripting. Well, we can't use parentheses, so try brackets:
(EQUAL? 1000[8] 512[10])
For historical compatibility, we also allow 512. to mean the same as
512[10] . Therefore "." means the same as "[10]". So extend this
notion to the floating-point notation:
3.14159265 means the same as 3[10]14159265
and now we have an unambiguous place to put the radix:
3[10]1415926535 approximately equals 3[8]11037552
If you really can't stand that, we could settle for 3.11037552[8],
where the "[...]" overrides the decimalness of the ".".
This still doesn't solve the problem of whether "E" is a hex digit or an
exponent marker. Well, the "E" serves two purposes" as a delimiter
between significand and exponent, and as a precision indicator (other
choices are "D" and perhaps "S", "F", "L", or whatever). One might wish
to measure precision in bits. So gobble down "<...>" for this purpose.
Then "E" is just an abbreviation for "<24>" or whatever:
Pi is approximately [8]311037552<24>+1
If "E" might be taken as a digit, then one must write "<24>" or "<E>".
Pretty horrible, huh?
--Guy
∂30-Jul-85 2036 GJC@MIT-MC.ARPA Ambiguous number syntax
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 30 Jul 85 20:35:57 PDT
Date: Tue, 30 Jul 85 22:59:41 EDT
From: George J. Carrette <GJC@MIT-MC.ARPA>
Subject: Ambiguous number syntax
To: gls@THINK-AQUINAS.ARPA
cc: SCHEME@MIT-MC.ARPA, Bartley%CSL60%ti-csl.csnet@CSNET-RELAY.ARPA,
MMeyer%CSL60%ti-csl.csnet@CSNET-RELAY.ARPA, GJS@MIT-OZ
In-reply-to: Msg of Mon 29 Jul 85 13:06 EDT from Guy Steele <gls at THINK-AQUINAS.ARPA>
Message-ID: <[MIT-MC.ARPA].594615.850730.GJC>
Fortunately there is always #.(J-RANDOM-NUMBER "...random syntax")
∂31-Jul-85 1159 @MIT-MC.ARPA:CPH@MIT-OZ identifiers and symbols
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 31 Jul 85 11:58:59 PDT
Received: from MIT-OZ by MIT-MC.ARPA via Chaosnet; 31 JUL 85 14:57:20 EDT
Date: Wed, 31 Jul 1985 14:52 EDT
Message-ID: <CPH.12131444141.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Snyder%hplabs.csnet@CSNET-RELAY.ARPA
Cc: Scheme@MIT-MC.ARPA
Subject: identifiers and symbols
In-reply-to: Msg of 30 Jul 1985 15:54-EDT from Snyder%hplabs.csnet at csnet-relay.arpa
Date: Tuesday, 30 July 1985 15:54-EDT
From: Snyder%hplabs.csnet at csnet-relay.arpa
To: cph at mit-mc.ARPA
Re: identifiers and symbols
Source-Info: From (or Sender) name not authenticated.
In reading the draft Scheme report, it appears that the possibility is left
open for identifiers and symbols to be distinct. For example, the first
paragraph in Section II.5 says that symbols are often used to represent
identifiers, implying that other alternatives are possible. Is this correct?
If so, are identifiers defined as objects (how do they behave)? Does read of
"X" return an identifier or a symbol?
Alan Snyder
Technically, these two types might be distinct. Practically speaking,
there seems little point in doing so. But there is no reason that the
report should contain this unnecessary bias.
On the other hand, since it is (perhaps) universally true that they
are not distinct, I guess that Will did not think the extra effort of
completely separating them was worth it. Trying to decide which gets
used where (e.g. in READ) might take some time. And if you just
assume that they are the same, then (I think) the rest of the report
is pretty consistent.
But I'm just guessing. I'll forward this to Scheme@MC, which will get
you a much wider range of opinions -- that is the best place to send
mail concerning the report, since everyone who helped make it will be
available to reply.
∂31-Jul-85 1445 JAR@MIT-MC.ARPA identifiers and symbols
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 31 Jul 85 14:45:30 PDT
Date: Wed, 31 Jul 85 17:46:03 EDT
From: Jonathan A Rees <JAR@MIT-MC.ARPA>
Subject: identifiers and symbols
To: Snyder%hplabs.csnet@CSNET-RELAY.ARPA
cc: SCHEME@MIT-MC.ARPA, CPH@MIT-OZ
Message-ID: <[MIT-MC.ARPA].595673.850731.JAR>
Date: Tuesday, 30 July 1985 15:54-EDT
From: Snyder%hplabs.csnet at csnet-relay.arpa
In reading the draft Scheme report, it appears that the
possibility is left open for identifiers and symbols to be
distinct. For example, the first paragraph in Section II.5 says
that symbols are often used to represent identifiers, implying
that other alternatives are possible. Is this correct? If so,
are identifiers defined as objects (how do they behave)? Does
read of "X" return an identifier or a symbol?
I think you're confusing domains which Lisp blurs, but that the report
takes care to distinguish. The beginning of section II.1, "special
forms," says that identifiers, whose syntax is given previously, have
two uses (i.e. occur in the grammar in the rhs of two productions): as
<expression>'s, where they name variables; and inside of <datum>'s,
where they notate symbols, a particular kind of value. Identifiers,
being syntactic, can no more be user-level objects (i.e. values) than
can combinations or special forms.
Your typical Lisp manual (including, I hate to say, the T manual) starts
out the other way around by saying that data (lists, symbols, numbers)
can be notated using character strings of a certain form, and then says
that data can be interpreted as being program: a symbol can be a
variable name, a list can be a combination, etc. The Scheme report asks
you to imagine that the fact that programs and data are notated pretty
similarly is coincidental. It never says that a program is "read" from
a file using a READ function, and then parsed and interpreted through a
separate mechanism. Conceivably some poor soul could translate the
grammar from the Scheme report into YACC, and write a Scheme system in
C, in which maybe identifiers are represented as arrays of small
integers, and symbols and lists never come into existence at all, except
when a (QUOTE ...) form is evaluated, STRING->SYMBOL is called, etc.
The representation of identifiers, like that of numbers, is completely
invisible to the user.
READ of "X" presumably invokes that part of the Scheme parser which
deals with the <datum> nonterminal, and returns the appropriate value,
as if you had evaluated (QUOTE X) instead of (READ ...); so the value
would be a symbol.
I think that the statement in section II.4, "Even Lisp and Scheme
programs are lists," while true in spirit, is not accurate. But it's
difficult to come up with a concise way to connect the two concepts.
You'd have to say something to the effect that any sequence of terminals
derivable from the nonterminal <expression> could also be derived from the
nonterminal <datum> (can this be inferred from the report? Can 'foo and
`(a ,b) be derived from <datum>?).
Sorry to be so pedantic... I hope this clarifies things.
Jonathan
∂01-Aug-85 0915 @MIT-MC.ARPA:BARTLEY%ti-csl.csnet@csnet-relay.arpa Re: identifiers and symbols
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 1 Aug 85 09:14:50 PDT
Received: from csnet-relay by MIT-MC.ARPA 1 Aug 85 12:05:09 EDT
Received: from ti-csl by csnet-relay.csnet id ad01020; 1 Aug 85 11:54 EDT
Date: 31 Jul 1985 1808-CDT
From: David Bartley <Bartley%CSL60%ti-csl.csnet@csnet-relay.arpa>
Subject: Re: identifiers and symbols
To: CPH%MIT-OZ@mit-mc.ARPA, Snyder%hplabs.csnet@csnet-relay.arpa
cc: Scheme@mit-mc.ARPA, Bartley%CSL60%ti-csl.csnet@csnet-relay.arpa
In-Reply-To: Your message of 31-Jul-85 1658-CDT
Received: from csl60 by ti-csl; Wed, 31 Jul 85 19:05 CST
In reading the draft Scheme report, it appears that the possibility is left
open for identifiers and symbols to be distinct. For example, the first
paragraph in Section II.5 says that symbols are often used to represent
identifiers, implying that other alternatives are possible. Is this correct?
If so, are identifiers defined as objects (how do they behave)? Does read of
"X" return an identifier or a symbol?
Alan Snyder
I think of an "identifier" as a non-terminal in the grammar, while a
"symbol" is a datatype, so identifiers are not objects, and READ of X
returns a symbol.
The reason identifiers and symbols are distinct is that we don't want to
impose the implementation requirement that a Scheme program must be
internally represented as an s-expression. In particular, an identifier in
a program may be lexically processed by a compiler without passing through
READ at all, and therefore need not be represented as a symbol. Having
identifiers and symbols obey the same syntax rules is just a way to
facilitate the representation of identifiers by symbols, but it doesn't
require it.
I periodically pick this nit because many non-Schemers confuse "symbols"
with "variables." Further distinguishing "symbols" from "identifiers" is
meaningful to me, and seems to be implied by Will's wording, but may be
more controversial. Does anyone else see things this way, or am I outside
the pale (again)?
David Bartley
-------
∂02-Aug-85 1338 @MIT-MC.ARPA:mw%brandeis.csnet@csnet-relay.arpa Re: identifiers and symbols
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 2 Aug 85 13:38:38 PDT
Received: from csnet-relay by MIT-MC.ARPA 2 Aug 85 16:39:03 EDT
Received: from brandeis by csnet-relay.csnet id aa09446; 2 Aug 85 16:31 EDT
Received: by brandeis.ARPA (4.12/4.7)
id AA00810; Fri, 2 Aug 85 11:46:14 edt
Date: 2 Aug 1985 11:39-EST
From: mw%brandeis.csnet@csnet-relay.arpa
In-Real-Life: Mitchell Wand,faculty
Subject: Re: identifiers and symbols
To: David Bartley <Bartley%CSL60%ti-csl.csnet@csnet-relay.arpa>
Cc: scheme@mit-mc.ARPA
Message-Id: <491845196/mw@brandeis>
In-Reply-To: David Bartley's message of 31 Jul 1985 1808-CDT
←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←
From BARTLEY%ti-csl.csnet%CSNET-RELAY@MIT-MC.ARPA Thu Aug 1 16:24:38 1985
Date: 31 Jul 1985 1808-CDT
From: David Bartley <Bartley%CSL60%ti-csl.csnet@CSNET-RELAY>
Subject: Re: identifiers and symbols
To: CPH%MIT-OZ@MIT-MC, Snyder%hplabs.csnet@CSNET-RELAY
Cc: Scheme@MIT-MC, Bartley%CSL60%ti-csl.csnet@CSNET-RELAY
Status: O
In reading the draft Scheme report, it appears that the possibility is left
open for identifiers and symbols to be distinct. For example, the first
paragraph in Section II.5 says that symbols are often used to represent
identifiers, implying that other alternatives are possible. Is this correct?
If so, are identifiers defined as objects (how do they behave)? Does read of
"X" return an identifier or a symbol?
Alan Snyder
I think of an "identifier" as a non-terminal in the grammar, while a
"symbol" is a datatype, so identifiers are not objects, and READ of X
returns a symbol.
The reason identifiers and symbols are distinct is that we don't want to
impose the implementation requirement that a Scheme program must be
internally represented as an s-expression. In particular, an identifier in
a program may be lexically processed by a compiler without passing through
READ at all, and therefore need not be represented as a symbol. Having
identifiers and symbols obey the same syntax rules is just a way to
facilitate the representation of identifiers by symbols, but it doesn't
require it.
I periodically pick this nit because many non-Schemers confuse "symbols"
with "variables." Further distinguishing "symbols" from "identifiers" is
meaningful to me, and seems to be implied by Will's wording, but may be
more controversial. Does anyone else see things this way, or am I outside
the pale (again)?
David Bartley
-------
←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←
Yes, I think you've got it right. Identifiers are part of the external
syntax of Scheme programs; symbols are a kind of data manipulated by
those programs. Symbols have an external representation as character
strings, which typically, though not necessarily, coincides with the
external syntax of identifiers.
One of the most important differences between Lisp and Scheme is, as
you point out, the rigid separation between programs and data, and
between syntax and semantics. Most Lisp dialects constrain programs to
be maintained as S-expressions; Scheme very carefully does not. For
more on this, see the paper by Muchnick and Pleban, A Semantic
Comparison of Lisp and Scheme, in the 1980 Lisp Conference.
-- Mitch
∂05-Aug-85 1836 @MIT-MC.ARPA:unc!dyb%unc.csnet@csnet-relay.arpa Re: identifiers and symbols
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 5 Aug 85 18:35:56 PDT
Received: from csnet-relay by MIT-MC.ARPA 5 Aug 85 21:36:53 EDT
Received: from unc by csnet-relay.csnet id ah10818; 5 Aug 85 21:29 EDT
Received: from unc (dopey) by thorin (4.12/4.7)
id AA15806; Mon, 5 Aug 85 00:03:04 edt
Received: by unc (4.12/4.7)
id AA25673; Mon, 5 Aug 85 00:03:23 edt
Date: Mon, 5 Aug 85 00:03:23 edt
From: Kent Dybvig <unc!dyb%unc.csnet@csnet-relay.arpa>
Message-Id: <8508050403.AA25673@unc>
To: Bartley%CSL60%ti-csl.csnet@csnet-relay.arpa,
mw%brandeis.csnet@csnet-relay.arpa
Subject: Re: identifiers and symbols
Cc: scheme@mit-mc.ARPA
In reading the draft Scheme report, it appears that the possibility is left
open for identifiers and symbols to be distinct. For example, the first
paragraph in Section II.5 says that symbols are often used to represent
identifiers, implying that other alternatives are possible. Is this correct?
If so, are identifiers defined as objects (how do they behave)? Does read of
"X" return an identifier or a symbol?
Alan Snyder
I think of an "identifier" as a non-terminal in the grammar, while a
"symbol" is a datatype, so identifiers are not objects, and READ of X
returns a symbol.
The reason identifiers and symbols are distinct is that we don't want to
impose the implementation requirement that a Scheme program must be
internally represented as an s-expression. In particular, an identifier in
a program may be lexically processed by a compiler without passing through
READ at all, and therefore need not be represented as a symbol. Having
identifiers and symbols obey the same syntax rules is just a way to
facilitate the representation of identifiers by symbols, but it doesn't
require it.
I periodically pick this nit because many non-Schemers confuse "symbols"
with "variables." Further distinguishing "symbols" from "identifiers" is
meaningful to me, and seems to be implied by Will's wording, but may be
more controversial. Does anyone else see things this way, or am I outside
the pale (again)?
David Bartley
-------
←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←
Yes, I think you've got it right. Identifiers are part of the external
syntax of Scheme programs; symbols are a kind of data manipulated by
those programs. Symbols have an external representation as character
strings, which typically, though not necessarily, coincides with the
external syntax of identifiers.
One of the most important differences between Lisp and Scheme is, as
you point out, the rigid separation between programs and data, and
between syntax and semantics. Most Lisp dialects constrain programs to
be maintained as S-expressions; Scheme very carefully does not. For
more on this, see the paper by Muchnick and Pleban, A Semantic
Comparison of Lisp and Scheme, in the 1980 Lisp Conference.
-- Mitch
←←←←←←←←←←←←←←←←←←
I think that we should point out that certain objects may be
translated into Scheme expressions, with emphasis on translation
(that is, say that it may require writing the object to a file and
handing the compiler the resulting file). If we loose the idea of
"program as data" people will wonder what we are still using all
these parentheses for.
To allow the potential for translation requires that we agree upon a
common representation for programs as data. The natural one is the
one that prints the way we expect, with symbols denoting identifiers
and special form keywords. The wording might go, "If a Scheme object
is to be translated into a Scheme program, identifiers are represented
by symbols, special forms are represented by lists, ..." This does
require the syntax for identifiers to be a subsyntax (?) of the syntax
for symbols.
In spite of the conclusions of Muchnick and Pleban, I believe that we
should support an object-level representation for Scheme programs.
One of the beauties of Scheme is the ability to write macro processors
and compilers for Scheme in Scheme (easily), and the lack of this
ability is the one thing I dislike most about ML.
Kent
∂05-Aug-85 1851 @MIT-MC.ARPA:CPH@MIT-OZ identifiers and symbols
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 5 Aug 85 18:51:22 PDT
Received: from MIT-OZ by MIT-MC.ARPA via Chaosnet; 5 AUG 85 21:51:34 EDT
Date: Mon, 5 Aug 1985 21:49 EDT
Message-ID: <CPH.12132830745.BABYL@MIT-OZ>
From: CPH%MIT-OZ@MIT-MC.ARPA
To: Kent Dybvig <unc!dyb%unc.csnet@CSNET-RELAY.ARPA>
Cc: Bartley%CSL60%ti-csl.csnet@CSNET-RELAY.ARPA,
mw%brandeis.csnet@CSNET-RELAY.ARPA, scheme@MIT-MC.ARPA
Subject: identifiers and symbols
In-reply-to: Msg of 5 Aug 1985 00:03-EDT from Kent Dybvig <unc!dyb%unc.csnet at csnet-relay.arpa>
Date: Monday, 5 August 1985 00:03-EDT
From: Kent Dybvig <unc!dyb%unc.csnet at csnet-relay.arpa>
I think that we should point out that certain objects may be
translated into Scheme expressions, with emphasis on translation
(that is, say that it may require writing the object to a file and
handing the compiler the resulting file).
I personally am opposed to any mention of files or compilers in such a
manner. These are completely orthogonal to what I consider the
essence of the programming language (and programming environment), and
serve only the cloud the real issues, not clear them up. Ideally I
would like an environment without files, and without any explicit
compilation, in which all of that non-essential stuff happens
transparently to me. I'm interested in writing and debugging
procedures and data structures, not files of characters.
If we lose the idea of "program as data" people will wonder what
we are still using all these parentheses for.
Independent of the "program as data" feature, those parentheses are
still an essential aspect of the SIMPLICITY of Scheme (and Lisp)
syntax. This is, I think, even more important than the fact that a
Scheme program is representable as a data structure. One can, for
example, represent a Pascal or C program as a data structure in one of
those languages (albeit clumsily), but that does not make the external
syntax any simpler.
To allow the potential for translation requires that we agree upon a
common representation for programs as data.
I think that this is completely irrelevant as we have not included the
EVAL procedure in the Scheme standard. Nothing else in the standard
relates to such a representation in any way.
∂09-Aug-85 1539 JAR@MIT-MC.ARPA Altering quoted structure
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Aug 85 15:39:30 PDT
Date: Fri, 9 Aug 85 18:40:58 EDT
From: Jonathan A Rees <JAR@MIT-MC.ARPA>
Subject: Altering quoted structure
To: SCHEME@MIT-MC.ARPA
Message-ID: <[MIT-MC.ARPA].607100.850809.JAR>
I would like to point out a small problem in an example in section II.4,
"Pairs and lists." The following interaction:
(define x '(a b c)) --> x
(define y x) --> y
(set-cdr! x 4) --> unspecified
x --> (a . 4)
(eq? x y) --> #!true
y --> (a . 4)
will not necessarily work in implementations (e.g., Yale's) where quoted
structure may be stored in read-only memory.
I don't think the report says anything about quoted structure being
immutable, but I think that it is very important that implementations be
allowed to make them be read-only. I recommend that the description of
QUOTE (which is perhaps too terse even for my taste) be amended
appropriately.
The example can easily be fixed: just write
(define x (list 'a 'b 'c))
instead of
(define x '(a b c)) .
While the report can only specify that modifying quoted structure "is an
error," I would consider it any implementation which doesn't detect such
modifications to be deficient. It isn't done because it's difficult.
Jonathan
∂09-Aug-85 1546 JAR@MIT-MC.ARPA (EQV? #\? #\?) ?
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Aug 85 15:46:05 PDT
Date: Fri, 9 Aug 85 18:47:31 EDT
From: Jonathan A Rees <JAR@MIT-MC.ARPA>
Subject: (EQV? #\? #\?) ?
To: SCHEME@MIT-MC.ARPA
Message-ID: <[MIT-MC.ARPA].607113.850809.JAR>
Could we agree that EQV? should do a CHAR=? comparison on characters?
Jonathan?
∂09-Aug-85 1549 JAR@MIT-MC.ARPA Altering quoted structure, addendum
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Aug 85 15:49:49 PDT
Date: Fri, 9 Aug 85 18:51:15 EDT
From: Jonathan A Rees <JAR@MIT-MC.ARPA>
Subject: Altering quoted structure, addendum
To: SCHEME@MIT-MC.ARPA
Message-ID: <[MIT-MC.ARPA].607118.850809.JAR>
The example
(define vec '#(0 (2 2 2 2) "Anna")) --> vec
(vector-set! vec 1 '("Sue" "Sue")) --> unspecified
vec --> #(0
("Sue" "Sue")
"Anna")
is also at fault, and can be fixed the same way as the other one.
Jonathan.
∂09-Aug-85 1618 @MIT-MC.ARPA:JINX@MIT-OZ (EQV? #\? #\?) ?
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Aug 85 16:18:48 PDT
Received: from MIT-OZ by MIT-MC.ARPA via Chaosnet; 9 AUG 85 19:20:04 EDT
Date: 9 Aug 1985 19:18 EDT (Fri)
Message-ID: <JINX.12133851721.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Jonathan A Rees <JAR@MIT-MC.ARPA>
Cc: SCHEME@MIT-MC.ARPA
Subject: (EQV? #\? #\?) ?
In-reply-to: Msg of 9 Aug 1985 18:47-EDT from Jonathan A Rees <JAR at MIT-MC.ARPA>
yes!!
∂09-Aug-85 1623 @MIT-MC.ARPA:JINX@MIT-OZ Altering quoted structure
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 9 Aug 85 16:23:11 PDT
Received: from MIT-OZ by MIT-MC.ARPA via Chaosnet; 9 AUG 85 19:24:22 EDT
Date: 9 Aug 1985 19:22 EDT (Fri)
Message-ID: <JINX.12133852458.BABYL@MIT-OZ>
From: Bill Rozas <JINX%MIT-OZ@MIT-MC.ARPA>
To: Jonathan A Rees <JAR@MIT-MC.ARPA>
Cc: SCHEME@MIT-MC.ARPA
Subject: Altering quoted structure
In-reply-to: Msg of 9 Aug 1985 18:40-EDT from Jonathan A Rees <JAR at MIT-MC.ARPA>
I agree with you even though MIT Scheme does not detect alterations
to quoted structure. I think the report should say it is an error to
modify them.
PS : What do you do about Gcing quoted structure if it is in read-only
memory? Is it not garbage-collectable? Is the garbage collector
special?
∂12-Aug-85 0745 JAR@MIT-MC.ARPA delay, force, cons-stream
Received: from MIT-MC.ARPA by SU-AI.ARPA with TCP; 12 Aug 85 07:45:45 PDT
Date: Mon, 12 Aug 85 10:47:18 EDT
From: Jonathan A Rees <JAR@MIT-MC.ARPA>
Subject: delay, force, cons-stream
To: SCHEME@MIT-MC.ARPA
Message-ID: <[MIT-MC.ARPA].609180.850812.JAR>
Could someone remind me why DELAY, FORCE, and CONS-STREAM aren't in the
RRReport, even non-essentially? This absence seems inconsistent with
the presence of SEQUENCE, which exists only because it appears in S&ICP.
DELAY, FORCE, and CONS-STREAM also are used in S&ICP.
Jonathan